diff options
author | Chunseok Lee <chunseok.lee@samsung.com> | 2020-03-04 18:09:24 +0900 |
---|---|---|
committer | Chunseok Lee <chunseok.lee@samsung.com> | 2020-03-04 18:09:24 +0900 |
commit | 302e6564a7a76109e1178207e44e45a58631c477 (patch) | |
tree | 6cc4bd95e5e438331fc2c53234af4ed0e0f3bc20 /runtime/contrib/pure_arm_compute/src | |
parent | bd11b24234d7d43dfe05a81c520aa01ffad06e42 (diff) | |
download | nnfw-302e6564a7a76109e1178207e44e45a58631c477.tar.gz nnfw-302e6564a7a76109e1178207e44e45a58631c477.tar.bz2 nnfw-302e6564a7a76109e1178207e44e45a58631c477.zip |
Imported Upstream version 1.1.0upstream/1.1.0submit/tizen/20200304.094649submit/tizen/20200304.093946submit/tizen/20200304.092919accepted/tizen/unified/20200305.051107
Diffstat (limited to 'runtime/contrib/pure_arm_compute/src')
164 files changed, 23536 insertions, 0 deletions
diff --git a/runtime/contrib/pure_arm_compute/src/compilation.cc b/runtime/contrib/pure_arm_compute/src/compilation.cc new file mode 100644 index 000000000..8cc86ebae --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/compilation.cc @@ -0,0 +1,6434 @@ +/* + * 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. + */ + +/** + * @file compilation.cc + * @brief This file contains ANeuralNetworksCompilation APIs and related classes + * @ingroup COM_AI_RUNTIME + */ + +#include <NeuralNetworks.h> + +// For CLKernelLibraryEx initialization +#include "arm_compute/core/CL/CLHelpers.h" +#include "arm_compute/core/CL/CLKernelLibrary.h" +#include "arm_compute/core/CL/CLKernelLibraryEx.h" + +#include <arm_compute/runtime/IFunction.h> +#include <arm_compute/runtime/CL/CLScheduler.h> +#include <arm_compute/runtime/CL/CLSubTensor.h> +#include <arm_compute/runtime/CL/CLFunctions.h> // Include all ARM Compute CL functions +#include <arm_compute/runtime/CL/CLFunctionsEx.h> // Include all ARM Compute EX CL functions + +#include <arm_compute/runtime/SubTensor.h> +#include <arm_compute/runtime/NEON/NEFunctions.h> // Include all ARM Compute NEON functions +#include <arm_compute/runtime/NEON/NEFunctionsEx.h> // Include all ARM Compute EX NEON functions + +#include "internal/arm_compute.h" +#include "internal/arm_compute/Cast.h" +#include "internal/arm_compute/matrix/View.h" +#include "internal/arm_compute/kernel/View.h" +#include "internal/nnapi/matrix/Reader.h" +#include "internal/nnapi/kernel/Reader.h" +#include "internal/nnapi/feature/Reader.h" +#include "internal/nnapi/feature/View.h" +#include "internal/nnapi/tensor/Reader.h" +#include "internal/arm_compute/feature/View.h" +#include "internal/arm_compute/tensor/View.h" + +#include <arm_compute/runtime/misc/functions/GenericReshapeLayer.h> +#include <arm_compute/runtime/misc/functions/GenericGather.h> + +#include "misc/matrix/IndexIterator.h" +#include "misc/kernel/IndexIterator.h" +#include "misc/feature/IndexIterator.h" +#include "misc/tensor/IndexIterator.h" + +#include <cpp14/memory.h> + +#include "compilation.h" +#include "model.h" +#include "logging.h" + +using namespace arm_compute::misc; + +template <typename T> T from_env(const char *); + +template <> bool from_env(const char *s) +{ + if (s == nullptr) + { + return false; + } + + return std::stoi(s) != 0; +} + +const char *to_string(const PaddingCode &code) +{ + assert((ANEURALNETWORKS_PADDING_SAME == code) || (ANEURALNETWORKS_PADDING_VALID == code)); + + switch (code) + { + case ANEURALNETWORKS_PADDING_SAME: + return "ANEURALNETWORKS_PADDING_SAME"; + case ANEURALNETWORKS_PADDING_VALID: + return "ANEURALNETWORKS_PADDING_VALID"; + } + + return nullptr; +} + +struct Padding +{ + uint32_t top; + uint32_t bottom; + uint32_t left; + uint32_t right; +}; + +struct Stride +{ + uint32_t vertical; + uint32_t horizontal; +}; + +Padding valid_padding(void) +{ + // + // ANEURALNETWORKS_PADDING_VALID + // + // VALID padding. No padding. + // + // When the input size is not evenly divisible by the filter size, + // the input at the end that could not fill the whole filter tile + // will simply be ignored. + // + Padding padding; + + padding.top = 0; + padding.bottom = 0; + padding.left = 0; + padding.right = 0; + + return padding; +} + +Padding same_padding(const nnfw::misc::feature::Shape &ifm_shape, + const nnfw::misc::feature::Shape &ofm_shape, const Stride &stride, uint32_t kw, + uint32_t kh) +{ + Padding padding; + + // ANEURALNETWORKS_PADDING_SAME (from NNAPI spec) + // + // SAME padding. Padding on both ends are the "same": + // + // padding_to_beginning = total_padding / 2 + // padding_to_end = (total_padding + 1)/2. + // + const int32_t vertical_needed_input = (ofm_shape.H - 1) * stride.vertical + kh; + const int32_t vertical_total_padding = std::max(0, vertical_needed_input - ifm_shape.H); + + const int32_t horizontal_needed_input = (ofm_shape.W - 1) * stride.horizontal + kw; + const int32_t horizontal_total_padding = std::max(0, horizontal_needed_input - ifm_shape.W); + + padding.top = vertical_total_padding / 2; + padding.bottom = (vertical_total_padding + 1) / 2; + padding.left = horizontal_total_padding / 2; + padding.right = (horizontal_total_padding + 1) / 2; + + return padding; +} + +::arm_compute::PadStrideInfo asPadStrideInfo(const Padding &padding, const Stride &stride) +{ + return ::arm_compute::PadStrideInfo{stride.horizontal, + stride.vertical, + padding.left, + padding.right, + padding.top, + padding.bottom, + ::arm_compute::DimensionRoundingType::FLOOR}; +} + +::arm_compute::ActivationLayerInfo asActInfo(FuseCode act) +{ + if (act == ANEURALNETWORKS_FUSED_NONE) + { + return ::arm_compute::ActivationLayerInfo(); + } + else if (act == ANEURALNETWORKS_FUSED_RELU) + { + return ::arm_compute::ActivationLayerInfo( + ::arm_compute::ActivationLayerInfo::ActivationFunction::RELU); + } + else if (act == ANEURALNETWORKS_FUSED_RELU1) + { + return ::arm_compute::ActivationLayerInfo( + ::arm_compute::ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, 1.0f, -1.0f); + } + else if (act == ANEURALNETWORKS_FUSED_RELU6) + { + return ::arm_compute::ActivationLayerInfo( + ::arm_compute::ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, 6.0f, 0.0f); + } + else + { + throw std::runtime_error("Not supported, yet"); + } +} + +struct IAllocationContext +{ + virtual ~IAllocationContext() = default; + + virtual ::arm_compute::ITensor *at(const ::internal::tflite::operand::Index &ind) const = 0; +}; + +#include "internal/IExecutionBuilder.h" + +using Initializer = std::function<void(::arm_compute::ITensor &)>; +using Stage = std::function<void(const IAllocationContext &, IExecutionBuilder &)>; + +using namespace std::placeholders; + +template <typename T> +static void initFeatureTensor(::arm_compute::ITensor &tensor, + const nnfw::misc::feature::Shape &feature_shape, + const uint8_t *feature_base, const size_t feature_size) +{ + const ::internal::nnapi::feature::Reader<T> from{ + feature_shape, reinterpret_cast<const T *>(feature_base), feature_size}; + ::internal::arm_compute::feature::View<T> into{&tensor}; + + ::nnfw::misc::feature::iterate(feature_shape) + << [&](uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) { + const auto value = from.at(batch, ch, row, col); + into.at(batch, ch, row, col) = value; + }; +} + +template <typename T> +static void initVectorTensor(::arm_compute::ITensor &tensor, const uint8_t *vec_base, + const size_t vec_size) +{ + for (uint32_t n = 0; n < vec_size; ++n) + { + const ::arm_compute::Coordinates coordinate{n}; + + T *into = reinterpret_cast<T *>(tensor.ptr_to_element(coordinate)); + + const T *from = reinterpret_cast<const T *>(vec_base) + n; + const auto value = *from; + + *into = value; + } +} + +template <typename T> +static void initTensor3D(::arm_compute::ITensor &tensor, + const nnfw::misc::tensor::Shape &tensor_shape, const uint8_t *tensor_base, + const size_t tensor_size) +{ + const ::internal::nnapi::tensor::Reader<T> from{ + tensor_shape, reinterpret_cast<const T *>(tensor_base), tensor_size}; + ::internal::arm_compute::tensor::View<T> into{&tensor}; + + ::nnfw::misc::tensor::iterate(tensor_shape) << [&](const nnfw::misc::tensor::Index &index_nnapi) { + ::nnfw::misc::tensor::Index index_ACL = ::nnfw::misc::tensor::copy_reverse(index_nnapi); + into.at(index_ACL) = from.at(index_nnapi); + }; +} + +template <typename T> +static void initMatrixTensor(::arm_compute::ITensor &tensor, + const nnfw::misc::matrix::Shape &matrix_shape, + const uint8_t *matrix_base, const size_t matrix_size) +{ + const ::internal::nnapi::matrix::Reader<T> from{ + matrix_shape, reinterpret_cast<const T *>(matrix_base), matrix_size}; + ::internal::arm_compute::matrix::View<T> into{&tensor}; + + ::nnfw::misc::matrix::iterate(matrix_shape) << [&](uint32_t row, uint32_t col) { + const auto value = from.at(row, col); + into.at(row, col) = value; + }; +} + +template <typename T> +static void initReorderVectorTensor(::arm_compute::ITensor &tensor, const uint8_t *vec_base, + const size_t vec_size) +{ + for (uint32_t n = 0; n < vec_size; ++n) + { + const ::arm_compute::Coordinates coordinate{ToARMComputeAxis(vec_size, n).value()}; + + T *into = reinterpret_cast<T *>(tensor.ptr_to_element(coordinate)); + + const T *from = reinterpret_cast<const T *>(vec_base) + n; + const auto value = *from; + + *into = value; + } +} + +template <typename T> +static void initKernelTensor(::arm_compute::ITensor &tensor, + const nnfw::misc::kernel::Shape &kernel_shape, + const uint8_t *kernel_base, const size_t kernel_size) +{ + const ::internal::nnapi::kernel::Reader<T> from{ + kernel_shape, reinterpret_cast<const T *>(kernel_base), kernel_size}; + ::internal::arm_compute::kernel::View<T> into{&tensor}; + + ::nnfw::misc::kernel::iterate(kernel_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; + }; +} + +/** + * @brief Structure to provide interface methods of compilation plan builder + */ +struct IPlanBuilder +{ + /** + * @brief Destruct IPlanBuilder object using default destructor + */ + virtual ~IPlanBuilder() = default; + + /** + * @brief Add TensorInfo with Shape Constraints + * @param [in] ind Index of operand + * @param [in] info TensorInfo value to set to index of operand + * @return N/A + */ + virtual void addShapeConstr(const ::internal::tflite::operand::Index &ind, + const ::arm_compute::TensorInfo &info) = 0; + /** + * @brief Add Subsumption constraints + * @param [in] ind Index of operand + * @param [in] base Index of base operand of Subsumption + * @param [in] offset Offset of Subsumption + * @param [in] shape Shape of Subsumption + * @param [in] extend_parent extend_parent value of Subsumption + * @return N/A + */ + virtual void addSubsumptionConstr(const ::internal::tflite::operand::Index &ind, + const ::internal::tflite::operand::Index &base, + const ::arm_compute::Coordinates &offset, + const ::arm_compute::TensorShape &shape, + bool extend_parent = false) = 0; + /** + * @brief Add Initializer lambda with ITensor param + * @param [in] ind Index of operand + * @param [in] initializer Initializer to add + * @return N/A + */ + virtual void addInitializer(const ::internal::tflite::operand::Index &ind, + const Initializer &initializer) = 0; + /** + * @brief Add Stage lambda with IAllocationContext and IExecutionBuilder params + * @param [in] stage Stage to add + * @return N/A + */ + virtual void addStage(const Stage &stage) = 0; +}; + +// +// ActivationBuilder +// +class ActivationBuilder +{ +public: + ActivationBuilder(IExecutionBuilder &builder) : _builder(builder) + { + // DO NOTHING + } + +private: + void appendReLU(::arm_compute::ITensor *tensor); + void appendReLU6(::arm_compute::ITensor *tensor); + void appendReLU1(::arm_compute::ITensor *tensor); + +public: + void append(FuseCode code, ::arm_compute::ITensor *tensor); + +private: + IExecutionBuilder &_builder; +}; + +void ActivationBuilder::appendReLU(::arm_compute::ITensor *ifm_alloc) +{ + const ::arm_compute::ActivationLayerInfo act_info{ + ::arm_compute::ActivationLayerInfo::ActivationFunction::RELU}; + + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLActivationLayer>(); + + fn->configure(CAST_CL(ifm_alloc), nullptr, act_info); + + _builder.append("ReLU", std::move(fn)); + } + else + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::NEActivationLayer>(); + + fn->configure(ifm_alloc, nullptr, act_info); + + _builder.append("ReLU", std::move(fn)); + } +} + +void ActivationBuilder::appendReLU1(::arm_compute::ITensor *ifm_alloc) +{ + const ::arm_compute::ActivationLayerInfo act_info{ + ::arm_compute::ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, 1.0f, -1.0f}; + + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLActivationLayer>(); + + fn->configure(CAST_CL(ifm_alloc), nullptr, act_info); + + _builder.append("ReLU1", std::move(fn)); + } + else + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::NEActivationLayer>(); + + fn->configure(ifm_alloc, nullptr, act_info); + + _builder.append("ReLU1", std::move(fn)); + } +} + +void ActivationBuilder::appendReLU6(::arm_compute::ITensor *ifm_alloc) +{ + const ::arm_compute::ActivationLayerInfo act_info{ + ::arm_compute::ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, 6.0f, 0.0f}; + + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLActivationLayer>(); + + fn->configure(CAST_CL(ifm_alloc), nullptr, act_info); + + _builder.append("ReLU6", std::move(fn)); + } + else + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::NEActivationLayer>(); + + fn->configure(ifm_alloc, nullptr, act_info); + + _builder.append("ReLU6", std::move(fn)); + } +} + +void ActivationBuilder::append(FuseCode code, ::arm_compute::ITensor *ifm_alloc) +{ + switch (code) + { + case ANEURALNETWORKS_FUSED_NONE: + { + // DO NOTHING + break; + } + case ANEURALNETWORKS_FUSED_RELU: + { + appendReLU(ifm_alloc); + break; + } + case ANEURALNETWORKS_FUSED_RELU1: + { + appendReLU1(ifm_alloc); + break; + } + case ANEURALNETWORKS_FUSED_RELU6: + { + appendReLU6(ifm_alloc); + break; + } + default: + { + throw std::runtime_error("Not supported, yet"); + } + } +} + +class Planner : public ::internal::tflite::op::NodeVisitor +{ +public: + Planner(const ::internal::tflite::operand::Set &ctx, IPlanBuilder &builder) + : _ctx{ctx}, _builder{builder} + { + // DO NOTHING + } + +public: + void visit(const ::internal::tflite::op::Add::Node &node) override; + void visit(const ::internal::tflite::op::Sub::Node &node) override; + void visit(const ::internal::tflite::op::Mul::Node &node) override; + void visit(const ::internal::tflite::op::Div::Node &node) override; + void visit(const ::internal::tflite::op::Conv2D::Implicit::Node &node) override; + void visit(const ::internal::tflite::op::Conv2D::Explicit::Node &node) override; + void visit(const ::internal::tflite::op::DepthwiseConv2D::Implicit::Node &node) override; + void visit(const ::internal::tflite::op::DepthwiseConv2D::Explicit::Node &node) override; + void visit(const ::internal::tflite::op::Dequantize::Node &node) override; + void visit(const ::internal::tflite::op::MaxPool2D::Implicit::Node &node) override; + void visit(const ::internal::tflite::op::MaxPool2D::Explicit::Node &node) override; + void visit(const ::internal::tflite::op::AvgPool2D::Implicit::Node &node) override; + void visit(const ::internal::tflite::op::AvgPool2D::Explicit::Node &node) override; + void visit(const ::internal::tflite::op::Concat::Node &node) override; + void visit(const ::internal::tflite::op::FullyConnected::Node &node) override; + void visit(const ::internal::tflite::op::ResizeBilinear::Node &node) override; + void visit(const ::internal::tflite::op::Reshape::Node &node) override; + void visit(const ::internal::tflite::op::Squeeze::Node &node) override; + void visit(const ::internal::tflite::op::Softmax::Node &node) override; + void visit(const ::internal::tflite::op::StridedSlice::Node &node) override; + void visit(const ::internal::tflite::op::ReduceMax::Node &node) override; + void visit(const ::internal::tflite::op::ReduceMin::Node &node) override; + void visit(const ::internal::tflite::op::Cast::Node &node) override; + void visit(const ::internal::tflite::op::TopKV2::Node &node) override; + void visit(const ::internal::tflite::op::Gather::Node &node) override; + void visit(const ::internal::tflite::op::PReLU::Node &node) override; + void visit(const ::internal::tflite::op::ReLU::Node &node) override; + void visit(const ::internal::tflite::op::ReLU1::Node &node) override; + void visit(const ::internal::tflite::op::ReLU6::Node &node) override; + void visit(const ::internal::tflite::op::Tanh::Node &node) override; + void visit(const ::internal::tflite::op::Logistic::Node &node) override; + void visit(const ::internal::tflite::op::Mean::Node &node) override; + void visit(const ::internal::tflite::op::RNN::Node &node) override; + void visit(const ::internal::tflite::op::Transpose::Node &node) override; + void visit(const ::internal::tflite::op::LSTM::Node &node) override; + void visit(const ::internal::tflite::op::Floor::Node &node) override; + void visit(const ::internal::tflite::op::Split::Node &node) override; + void visit(const ::internal::tflite::op::ArgMax::Node &node) override; + void visit(const ::internal::tflite::op::RSQRT::Node &node) override; + void visit(const ::internal::tflite::op::SQRT::Node &node) override; + void visit(const ::internal::tflite::op::Pad::Node &node) override; + void visit(const ::internal::tflite::op::SpaceToDepth::Node &node) override; + void visit(const ::internal::tflite::op::SpaceToBatchND::Node &node) override; + void visit(const ::internal::tflite::op::BatchToSpaceNd::Node &node) override; + void visit(const ::internal::tflite::op::L2Pool2D::Implicit::Node &node) override; + void visit(const ::internal::tflite::op::L2Pool2D::Explicit::Node &node) override; + void visit(const ::internal::tflite::op::EmbeddingLookup::Node &node) override; + void visit(const ::internal::tflite::op::HashtableLookup::Node &node) override; + void visit(const ::internal::tflite::op::L2Normalization::Node &node) override; + void visit(const ::internal::tflite::op::SquaredDifference::Node &node) override; + void visit(const ::internal::tflite::op::LocalResponseNormalization::Node &node) override; + void visit(const ::internal::tflite::op::DepthToSpace::Node &node) override; + void visit(const ::internal::tflite::op::Unpack::Node &node) override; + void visit(const ::internal::tflite::op::Neg::Node &node) override; + void visit(const ::internal::tflite::op::Exp::Node &node) override; + void visit(const ::internal::tflite::op::ReduceSum::Node &node) override; + void visit(const ::internal::tflite::op::Equal::Node &node) override; + void visit(const ::internal::tflite::op::TransposeConv::Node &node) override; + void visit(const ::internal::tflite::op::Pack::Node &node) override; + void visit(const ::internal::tflite::op::Abs::Node &node) override; + void visit(const ::internal::tflite::op::NotEqual::Node &node) override; + void visit(const ::internal::tflite::op::LogicalAnd::Node &node) override; + void visit(const ::internal::tflite::op::LogicalNot::Node &node) override; + void visit(const ::internal::tflite::op::LogicalOr::Node &node) override; + +private: + const ::internal::tflite::operand::Set &_ctx; + IPlanBuilder &_builder; +}; + +void Planner::visit(const ::internal::tflite::op::Add::Node &node) +{ + const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index}; + const ::internal::tflite::operand::Index lhs_index{node.param().lhs_index}; + const ::internal::tflite::operand::Index rhs_index{node.param().rhs_index}; + const ::internal::tflite::operand::Index activation_index{node.param().activation_index}; + + // TODO Should move to the place where the operand is handled, if it is possible. + // Set Shape Constraints and TensorInfo + _builder.addShapeConstr( + ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(), + _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint())); + + if (!(_ctx.at(lhs_index).shape() == _ctx.at(rhs_index).shape())) + { + const auto broadcast_rank = + std::max(_ctx.at(lhs_index).shape().rank(), _ctx.at(rhs_index).shape().rank()); + const_cast<::internal::tflite::operand::Shape &>(_ctx.at(lhs_index).shape()) + .extendRank(broadcast_rank); + const_cast<::internal::tflite::operand::Shape &>(_ctx.at(rhs_index).shape()) + .extendRank(broadcast_rank); + } + _builder.addShapeConstr( + lhs_index, asTensorInfo(asTensorShape(_ctx.at(lhs_index).shape()), _ctx.at(lhs_index).type(), + _ctx.at(lhs_index).scale(), _ctx.at(lhs_index).zeroPoint())); + _builder.addShapeConstr( + rhs_index, asTensorInfo(asTensorShape(_ctx.at(rhs_index).shape()), _ctx.at(rhs_index).type(), + _ctx.at(rhs_index).scale(), _ctx.at(rhs_index).zeroPoint())); + + // Construct operation parameters + struct Param + { + int ofm_index; + int lhs_index; + int rhs_index; + + FuseCode activation; + }; + + Param param; + + param.ofm_index = ofm_index.asInt(); + param.lhs_index = lhs_index.asInt(); + param.rhs_index = rhs_index.asInt(); + + param.activation = static_cast<FuseCode>(_ctx.at(activation_index).asScalar<int32_t>()); + + const auto lhs_shape = _ctx.at(lhs_index).shape(); + const auto rhs_shape = _ctx.at(rhs_index).shape(); + auto stage = [param, lhs_shape, rhs_shape](const IAllocationContext &ctx, + IExecutionBuilder &builder) { + auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index}); + auto lhs_alloc = ctx.at(::internal::tflite::operand::Index{param.lhs_index}); + auto rhs_alloc = ctx.at(::internal::tflite::operand::Index{param.rhs_index}); + + std::unique_ptr<::arm_compute::IFunction> fn; + + { + if (::internal::arm_compute::isGpuMode()) + { + auto l = nnfw::cpp14::make_unique<::arm_compute::CLArithmeticAddition>(); + + // TODO Decide ConvertPolicy (WARP? SATURATE?) according to NN API specification + l->configure(CAST_CL(lhs_alloc), CAST_CL(rhs_alloc), CAST_CL(ofm_alloc), + ::arm_compute::ConvertPolicy::SATURATE); + + fn = std::move(l); + } + else // NEON + { + auto l = nnfw::cpp14::make_unique<::arm_compute::NEArithmeticAddition>(); + + // TODO Decide ConvertPolicy (WARP? SATURATE?) according to NN API specification + l->configure(lhs_alloc, rhs_alloc, ofm_alloc, ::arm_compute::ConvertPolicy::SATURATE); + + fn = std::move(l); + } + } + + builder.append("Add", std::move(fn)); + + ActivationBuilder{builder}.append(param.activation, ofm_alloc); + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::Sub::Node &node) +{ + const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index}; + const ::internal::tflite::operand::Index lhs_index{node.param().lhs_index}; + const ::internal::tflite::operand::Index rhs_index{node.param().rhs_index}; + const ::internal::tflite::operand::Index activation_index{node.param().activation_index}; + + // Set Shape Constraints and TensorInfo + _builder.addShapeConstr( + ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(), + _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint())); + + if (!(_ctx.at(lhs_index).shape() == _ctx.at(rhs_index).shape())) + { + const auto broadcast_rank = + std::max(_ctx.at(lhs_index).shape().rank(), _ctx.at(rhs_index).shape().rank()); + const_cast<::internal::tflite::operand::Shape &>(_ctx.at(lhs_index).shape()) + .extendRank(broadcast_rank); + const_cast<::internal::tflite::operand::Shape &>(_ctx.at(rhs_index).shape()) + .extendRank(broadcast_rank); + } + _builder.addShapeConstr( + lhs_index, asTensorInfo(asTensorShape(_ctx.at(lhs_index).shape()), _ctx.at(lhs_index).type(), + _ctx.at(lhs_index).scale(), _ctx.at(lhs_index).zeroPoint())); + _builder.addShapeConstr( + rhs_index, asTensorInfo(asTensorShape(_ctx.at(rhs_index).shape()), _ctx.at(rhs_index).type(), + _ctx.at(rhs_index).scale(), _ctx.at(rhs_index).zeroPoint())); + + // Construct operation parameters + struct Param + { + int ofm_index; + int lhs_index; + int rhs_index; + + FuseCode activation; + }; + + Param param; + + param.ofm_index = ofm_index.asInt(); + param.lhs_index = lhs_index.asInt(); + param.rhs_index = rhs_index.asInt(); + + param.activation = static_cast<FuseCode>(_ctx.at(activation_index).asScalar<int32_t>()); + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index}); + auto lhs_alloc = ctx.at(::internal::tflite::operand::Index{param.lhs_index}); + auto rhs_alloc = ctx.at(::internal::tflite::operand::Index{param.rhs_index}); + + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLArithmeticSubtraction>(); + + // TODO Decide ConvertPolicy (WARP? SATURATE?) according to NN API specification + fn->configure(CAST_CL(lhs_alloc), CAST_CL(rhs_alloc), CAST_CL(ofm_alloc), + ::arm_compute::ConvertPolicy::SATURATE); + + builder.append("Sub", std::move(fn)); + } + else // NEON + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::NEArithmeticSubtraction>(); + + // TODO Decide ConvertPolicy (WARP? SATURATE?) according to NN API specification + fn->configure(lhs_alloc, rhs_alloc, ofm_alloc, ::arm_compute::ConvertPolicy::SATURATE); + + builder.append("Sub", std::move(fn)); + } + + ActivationBuilder{builder}.append(param.activation, ofm_alloc); + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::Mul::Node &node) +{ + const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index}; + const ::internal::tflite::operand::Index lhs_index{node.param().lhs_index}; + const ::internal::tflite::operand::Index rhs_index{node.param().rhs_index}; + const ::internal::tflite::operand::Index activation_index{node.param().activation_index}; + + if (_ctx.at(ofm_index).scale() > 0) + { + assert(_ctx.at(ofm_index).scale() > _ctx.at(lhs_index).scale() * _ctx.at(rhs_index).scale()); + } + // Set Shape Constraints and TensorInfo + _builder.addShapeConstr( + ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(), + _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint())); + + if (!(_ctx.at(lhs_index).shape() == _ctx.at(rhs_index).shape())) + { + const auto broadcast_rank = + std::max(_ctx.at(lhs_index).shape().rank(), _ctx.at(rhs_index).shape().rank()); + const_cast<::internal::tflite::operand::Shape &>(_ctx.at(lhs_index).shape()) + .extendRank(broadcast_rank); + const_cast<::internal::tflite::operand::Shape &>(_ctx.at(rhs_index).shape()) + .extendRank(broadcast_rank); + } + _builder.addShapeConstr( + lhs_index, asTensorInfo(asTensorShape(_ctx.at(lhs_index).shape()), _ctx.at(lhs_index).type(), + _ctx.at(lhs_index).scale(), _ctx.at(lhs_index).zeroPoint())); + _builder.addShapeConstr( + rhs_index, asTensorInfo(asTensorShape(_ctx.at(rhs_index).shape()), _ctx.at(rhs_index).type(), + _ctx.at(rhs_index).scale(), _ctx.at(rhs_index).zeroPoint())); + + struct Param + { + int ofm_index; + int lhs_index; + int rhs_index; + + FuseCode activation; + }; + + Param param; + + param.ofm_index = ofm_index.asInt(); + param.lhs_index = lhs_index.asInt(); + param.rhs_index = rhs_index.asInt(); + + param.activation = static_cast<FuseCode>(_ctx.at(activation_index).asScalar<int32_t>()); + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + + auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index}); + auto lhs_input_alloc = ctx.at(::internal::tflite::operand::Index{param.lhs_index}); + auto rhs_input_alloc = ctx.at(::internal::tflite::operand::Index{param.rhs_index}); + + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLPixelWiseMultiplication>(); + + fn->configure(CAST_CL(lhs_input_alloc), CAST_CL(rhs_input_alloc), CAST_CL(output_alloc), + 1.0, // scale + arm_compute::ConvertPolicy::SATURATE, + arm_compute::RoundingPolicy::TO_NEAREST_EVEN); + + builder.append("Mul", std::move(fn)); + } + else // NEON + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::NEPixelWiseMultiplication>(); + + fn->configure(lhs_input_alloc, rhs_input_alloc, output_alloc, + 1.0, // scale + arm_compute::ConvertPolicy::SATURATE, arm_compute::RoundingPolicy::TO_ZERO); + + builder.append("Mul", std::move(fn)); + } + + ActivationBuilder{builder}.append(param.activation, output_alloc); + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::Div::Node &node) +{ + const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index}; + + const ::internal::tflite::operand::Index lhs_index{node.param().lhs_index}; + const ::internal::tflite::operand::Index rhs_index{node.param().rhs_index}; + + const ::internal::tflite::operand::Index activation_index{node.param().activation_index}; + + // Set Shape Constraints and TensorInfo + _builder.addShapeConstr( + ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(), + _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint())); + + if (!(_ctx.at(lhs_index).shape() == _ctx.at(rhs_index).shape())) + { + const auto broadcast_rank = + std::max(_ctx.at(lhs_index).shape().rank(), _ctx.at(rhs_index).shape().rank()); + const_cast<::internal::tflite::operand::Shape &>(_ctx.at(lhs_index).shape()) + .extendRank(broadcast_rank); + const_cast<::internal::tflite::operand::Shape &>(_ctx.at(rhs_index).shape()) + .extendRank(broadcast_rank); + } + + _builder.addShapeConstr( + lhs_index, asTensorInfo(asTensorShape(_ctx.at(lhs_index).shape()), _ctx.at(lhs_index).type(), + _ctx.at(lhs_index).scale(), _ctx.at(lhs_index).zeroPoint())); + _builder.addShapeConstr( + rhs_index, asTensorInfo(asTensorShape(_ctx.at(rhs_index).shape()), _ctx.at(rhs_index).type(), + _ctx.at(rhs_index).scale(), _ctx.at(rhs_index).zeroPoint())); + + // Construct operation parameters + struct Param + { + int ofm_index; + int lhs_index; + int rhs_index; + + FuseCode activation; + }; + + Param param; + + param.ofm_index = ofm_index.asInt(); + param.lhs_index = lhs_index.asInt(); + param.rhs_index = rhs_index.asInt(); + + param.activation = static_cast<FuseCode>(_ctx.at(activation_index).asScalar<int32_t>()); + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index}); + auto lhs_alloc = ctx.at(::internal::tflite::operand::Index{param.lhs_index}); + auto rhs_alloc = ctx.at(::internal::tflite::operand::Index{param.rhs_index}); + + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLArithmeticDivision>(); + + fn->configure(CAST_CL(lhs_alloc), CAST_CL(rhs_alloc), CAST_CL(ofm_alloc)); + + builder.append("Div", std::move(fn)); + } + else + throw std::runtime_error("Not supported, yet"); + + ActivationBuilder{builder}.append(param.activation, ofm_alloc); + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::Conv2D::Implicit::Node &node) +{ + const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index}; + + const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index}; + const ::internal::tflite::operand::Index ker_index{node.param().ker_index}; + const ::internal::tflite::operand::Index bias_index{node.param().bias_index}; + + const ::internal::tflite::operand::Index vstride_index{node.param().vstride_index}; + const ::internal::tflite::operand::Index hstride_index{node.param().hstride_index}; + + const ::internal::tflite::operand::Index padding_index{node.param().padding_index}; + const ::internal::tflite::operand::Index activation_index{node.param().activation_index}; + + const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(); + const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(); + const auto ker_shape = _ctx.at(ker_index).shape().asKernel(); + const auto bias_size = _ctx.at(bias_index).shape().asVector(); + + const PaddingCode padding_type = + static_cast<PaddingCode>(_ctx.at(padding_index).asScalar<int32_t>()); + + Stride stride; + + stride.vertical = _ctx.at(vstride_index).asScalar<int32_t>(); + stride.horizontal = _ctx.at(hstride_index).asScalar<int32_t>(); + + assert((ANEURALNETWORKS_PADDING_SAME == padding_type) || + (ANEURALNETWORKS_PADDING_VALID == padding_type)); + + // TODO Should move to the place where the operand is handled, if it is possible. + // Set Shape Constraints and TensorInfo + _builder.addShapeConstr( + ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(), + _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint())); + _builder.addShapeConstr( + ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(), + _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint())); + _builder.addShapeConstr( + ker_index, asTensorInfo(asTensorShape(_ctx.at(ker_index).shape()), _ctx.at(ker_index).type(), + _ctx.at(ker_index).scale(), _ctx.at(ker_index).zeroPoint())); + _builder.addShapeConstr(bias_index, + asTensorInfo(asTensorShape(_ctx.at(bias_index).shape()), + _ctx.at(bias_index).type(), _ctx.at(bias_index).scale(), + _ctx.at(bias_index).zeroPoint())); + + // Set initializer for kernel + { + auto ker_base = _ctx.at(ker_index).data().base(); + auto ker_size = _ctx.at(ker_index).data().size(); + auto ker_type = _ctx.at(ker_index).type(); + + switch (ker_type) + { + case ANEURALNETWORKS_TENSOR_FLOAT32: + { + auto initializer = std::bind(initKernelTensor<float>, _1, ker_shape, ker_base, ker_size); + _builder.addInitializer(ker_index, initializer); + break; + } + case ANEURALNETWORKS_TENSOR_QUANT8_ASYMM: + { + auto initializer = std::bind(initKernelTensor<uint8_t>, _1, ker_shape, ker_base, ker_size); + _builder.addInitializer(ker_index, initializer); + break; + } + default: + { + throw std::runtime_error("Not supported"); + } + } + } + + // Set initializer for bias + { + auto bias_base = _ctx.at(bias_index).data().base(); + auto bias_type = _ctx.at(bias_index).type(); + + switch (bias_type) + { + case ANEURALNETWORKS_TENSOR_FLOAT32: + { + auto initializer = std::bind(initVectorTensor<float>, _1, bias_base, bias_size); + _builder.addInitializer(bias_index, initializer); + break; + } + case ANEURALNETWORKS_TENSOR_INT32: + { + auto initializer = std::bind(initVectorTensor<int32_t>, _1, bias_base, bias_size); + _builder.addInitializer(bias_index, initializer); + break; + } + default: + { + throw std::runtime_error("Not supported"); + } + } + } + + // Construct operation parameters + struct Param + { + int ofm_index; + int ifm_index; + int ker_index; + int bias_index; + + Padding padding; + Stride stride; + + FuseCode activation; + }; + + Param param; + + param.ofm_index = ofm_index.asInt(); + param.ifm_index = ifm_index.asInt(); + param.ker_index = ker_index.asInt(); + param.bias_index = bias_index.asInt(); + + param.stride = stride; + param.padding = (padding_type == ANEURALNETWORKS_PADDING_SAME) + ? same_padding(ifm_shape, ofm_shape, stride, ker_shape.W, ker_shape.H) + : valid_padding(); + + param.activation = static_cast<FuseCode>(_ctx.at(activation_index).asScalar<int32_t>()); + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index}); + auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index}); + auto ker_alloc = ctx.at(::internal::tflite::operand::Index{param.ker_index}); + auto bias_alloc = ctx.at(::internal::tflite::operand::Index{param.bias_index}); + + const auto conv_info = asPadStrideInfo(param.padding, param.stride); + const auto fused_act = asActInfo(param.activation); + + if (::internal::arm_compute::isGpuMode()) + { + std::unique_ptr<::arm_compute::CLConvolutionLayer> fn{new ::arm_compute::CLConvolutionLayer}; + + // To pass the fused_act parameter, it calls the WeightsInfo() and Size2D(1U, 1U) (dilation) + // functions like the default parameter. + fn->configure(CAST_CL(ifm_alloc), CAST_CL(ker_alloc), CAST_CL(bias_alloc), CAST_CL(ofm_alloc), + conv_info, ::arm_compute::WeightsInfo(), ::arm_compute::Size2D(1U, 1U), + fused_act); + + builder.append("Conv2D", std::move(fn)); + } + else + { + std::unique_ptr<::arm_compute::NEConvolutionLayer> fn{new ::arm_compute::NEConvolutionLayer}; + + // To pass the fused_act parameter, it calls the WeightsInfo() and Size2D(1U, 1U) (dilation) + // functions like the default parameter. + fn->configure(ifm_alloc, ker_alloc, bias_alloc, ofm_alloc, conv_info, + ::arm_compute::WeightsInfo(), ::arm_compute::Size2D(1U, 1U), fused_act); + + builder.append("Conv2D", std::move(fn)); + } + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::Conv2D::Explicit::Node &node) +{ + const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index}; + + const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index}; + const ::internal::tflite::operand::Index ker_index{node.param().ker_index}; + const ::internal::tflite::operand::Index bias_index{node.param().bias_index}; + + const ::internal::tflite::operand::Index vstride_index{node.param().vstride_index}; + const ::internal::tflite::operand::Index hstride_index{node.param().hstride_index}; + + const ::internal::tflite::operand::Index padding_left_index{node.param().padding_left_index}; + const ::internal::tflite::operand::Index padding_right_index{node.param().padding_right_index}; + const ::internal::tflite::operand::Index padding_top_index{node.param().padding_top_index}; + const ::internal::tflite::operand::Index padding_bottom_index{node.param().padding_bottom_index}; + + const ::internal::tflite::operand::Index activation_index{node.param().activation_index}; + + const int32_t padding_left = _ctx.at(padding_left_index).asScalar<int32_t>(); + const int32_t padding_right = _ctx.at(padding_right_index).asScalar<int32_t>(); + const int32_t padding_top = _ctx.at(padding_top_index).asScalar<int32_t>(); + const int32_t padding_bottom = _ctx.at(padding_bottom_index).asScalar<int32_t>(); + + Stride stride; + + stride.vertical = _ctx.at(vstride_index).asScalar<int32_t>(); + stride.horizontal = _ctx.at(hstride_index).asScalar<int32_t>(); + + // TODO Should move to the place where the operand is handled, if it is possible. + // Set Shape Constraints and TensorInfo + _builder.addShapeConstr( + ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(), + _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint())); + _builder.addShapeConstr( + ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(), + _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint())); + _builder.addShapeConstr( + ker_index, asTensorInfo(asTensorShape(_ctx.at(ker_index).shape()), _ctx.at(ker_index).type(), + _ctx.at(ker_index).scale(), _ctx.at(ker_index).zeroPoint())); + _builder.addShapeConstr(bias_index, + asTensorInfo(asTensorShape(_ctx.at(bias_index).shape()), + _ctx.at(bias_index).type(), _ctx.at(bias_index).scale(), + _ctx.at(bias_index).zeroPoint())); + + // Set initializer for kernel + // Workaround for https://github.sec.samsung.net/STAR/nnfw/issues/2319 + if (_ctx.at(ker_index).hasData()) + { + 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(); + auto ker_type = _ctx.at(ker_index).type(); + + switch (ker_type) + { + case ANEURALNETWORKS_TENSOR_FLOAT32: + { + auto initializer = std::bind(initKernelTensor<float>, _1, ker_shape, ker_base, ker_size); + _builder.addInitializer(ker_index, initializer); + break; + } + case ANEURALNETWORKS_TENSOR_QUANT8_ASYMM: + { + auto initializer = std::bind(initKernelTensor<uint8_t>, _1, ker_shape, ker_base, ker_size); + _builder.addInitializer(ker_index, initializer); + break; + } + default: + { + throw std::runtime_error("Not supported"); + } + } + } + + // Set initializer for bias + // See above comment. + if (_ctx.at(bias_index).hasData()) + { + const auto bias_size = _ctx.at(bias_index).shape().asVector(); + auto bias_base = _ctx.at(bias_index).data().base(); + auto bias_type = _ctx.at(bias_index).type(); + + switch (bias_type) + { + case ANEURALNETWORKS_TENSOR_FLOAT32: + { + auto initializer = std::bind(initVectorTensor<float>, _1, bias_base, bias_size); + _builder.addInitializer(bias_index, initializer); + break; + } + case ANEURALNETWORKS_TENSOR_INT32: + { + auto initializer = std::bind(initVectorTensor<int32_t>, _1, bias_base, bias_size); + _builder.addInitializer(bias_index, initializer); + break; + } + default: + { + throw std::runtime_error("Not supported"); + } + } + } + + // Construct operation parameters + struct Param + { + int ofm_index; + int ifm_index; + int ker_index; + int bias_index; + + Padding padding; + Stride stride; + + FuseCode activation; + }; + + Param param; + + param.ofm_index = ofm_index.asInt(); + param.ifm_index = ifm_index.asInt(); + param.ker_index = ker_index.asInt(); + param.bias_index = bias_index.asInt(); + + param.stride = stride; + + param.padding.left = padding_left; + param.padding.right = padding_right; + param.padding.top = padding_top; + param.padding.bottom = padding_bottom; + + param.activation = static_cast<FuseCode>(_ctx.at(activation_index).asScalar<int32_t>()); + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index}); + auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index}); + auto ker_alloc = ctx.at(::internal::tflite::operand::Index{param.ker_index}); + auto bias_alloc = ctx.at(::internal::tflite::operand::Index{param.bias_index}); + + const auto conv_info = asPadStrideInfo(param.padding, param.stride); + const auto fused_act = asActInfo(param.activation); + + if (::internal::arm_compute::isGpuMode()) + { + std::unique_ptr<::arm_compute::CLConvolutionLayer> fn{new ::arm_compute::CLConvolutionLayer}; + + // To pass the fused_act parameter, it calls the WeightsInfo() and Size2D(1U, 1U) (dilation) + // functions like the default parameter. + fn->configure(CAST_CL(ifm_alloc), CAST_CL(ker_alloc), CAST_CL(bias_alloc), CAST_CL(ofm_alloc), + conv_info, ::arm_compute::WeightsInfo(), ::arm_compute::Size2D(1U, 1U), + fused_act); + + builder.append("Conv2D", std::move(fn)); + } + else + { + std::unique_ptr<::arm_compute::NEConvolutionLayer> fn{new ::arm_compute::NEConvolutionLayer}; + + // To pass the fused_act parameter, it calls the WeightsInfo() and Size2D(1U, 1U) (dilation) + // functions like the default parameter. + fn->configure(ifm_alloc, ker_alloc, bias_alloc, ofm_alloc, conv_info, + ::arm_compute::WeightsInfo(), ::arm_compute::Size2D(1U, 1U), fused_act); + + builder.append("Conv2D", std::move(fn)); + } + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::DepthwiseConv2D::Implicit::Node &node) +{ + const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index}; + + const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index}; + const ::internal::tflite::operand::Index ker_index{node.param().ker_index}; + const ::internal::tflite::operand::Index bias_index{node.param().bias_index}; + + const ::internal::tflite::operand::Index vstride_index{node.param().vstride_index}; + const ::internal::tflite::operand::Index hstride_index{node.param().hstride_index}; + + const ::internal::tflite::operand::Index padding_index{node.param().padding_index}; + const ::internal::tflite::operand::Index multiplier_index{node.param().multiplier_index}; + const ::internal::tflite::operand::Index activation_index{node.param().activation_index}; + + const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(); + + const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(); + const auto ker_shape = _ctx.at(ker_index).shape().asFeature(); + const auto bias_size = _ctx.at(bias_index).shape().asVector(); + + auto multiplier = _ctx.at(multiplier_index).asScalar<int>(); + + assert(ker_shape.C == bias_size); + assert(ker_shape.C == ifm_shape.C * multiplier); + + const PaddingCode padding_type = + static_cast<PaddingCode>(_ctx.at(padding_index).asScalar<int32_t>()); + + Stride stride; + + stride.vertical = _ctx.at(vstride_index).asScalar<int32_t>(); + stride.horizontal = _ctx.at(hstride_index).asScalar<int32_t>(); + + assert((ANEURALNETWORKS_PADDING_SAME == padding_type) || + (ANEURALNETWORKS_PADDING_VALID == padding_type)); + + // TODO Should move to the place where the operand is handled, if it is possible. + // Set Shape Constraints and TensorInfo + _builder.addShapeConstr( + ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(), + _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint())); + _builder.addShapeConstr( + ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(), + _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint())); + // NOTE DepthwiseConv2D kernel is of shape [1, KER_W, KER_H, IFM_C * MULTIPLIER] + _builder.addShapeConstr( + ker_index, asTensorInfo(asTensorShape(_ctx.at(ker_index).shape()), _ctx.at(ker_index).type(), + _ctx.at(ker_index).scale(), _ctx.at(ker_index).zeroPoint())); + _builder.addShapeConstr(bias_index, + asTensorInfo(asTensorShape(_ctx.at(bias_index).shape()), + _ctx.at(bias_index).type(), _ctx.at(bias_index).scale(), + _ctx.at(bias_index).zeroPoint())); + + // Construct operation parameters + struct Param + { + int ofm_index; + int ifm_index; + int ker_index; + int bias_index; + + Padding padding; + Stride stride; + + int multipler; + FuseCode activation; + }; + + Param param; + + param.ofm_index = ofm_index.asInt(); + param.ifm_index = ifm_index.asInt(); + param.ker_index = ker_index.asInt(); + param.bias_index = bias_index.asInt(); + + param.stride = stride; + param.padding = (padding_type == ANEURALNETWORKS_PADDING_SAME) + ? same_padding(ifm_shape, ofm_shape, stride, ker_shape.W, ker_shape.H) + : valid_padding(); + + param.multipler = multiplier; + param.activation = static_cast<FuseCode>(_ctx.at(activation_index).asScalar<int32_t>()); + + VERBOSE(DepthwiseConv2D) << "OFM_C: " << ofm_shape.C << std::endl; + VERBOSE(DepthwiseConv2D) << "OFM_H: " << ofm_shape.H << std::endl; + VERBOSE(DepthwiseConv2D) << "OFM_W: " << ofm_shape.W << std::endl; + + VERBOSE(DepthwiseConv2D) << "IFM_C: " << ifm_shape.C << std::endl; + VERBOSE(DepthwiseConv2D) << "IFM_H: " << ifm_shape.H << std::endl; + VERBOSE(DepthwiseConv2D) << "IFM_W: " << ifm_shape.W << std::endl; + + VERBOSE(DepthwiseConv2D) << "KER_C: " << ker_shape.C << std::endl; + VERBOSE(DepthwiseConv2D) << "KER_H: " << ker_shape.H << std::endl; + VERBOSE(DepthwiseConv2D) << "KER_W: " << ker_shape.W << std::endl; + + VERBOSE(DepthwiseConv2D) << "STRIDE_H: " << param.stride.vertical << std::endl; + VERBOSE(DepthwiseConv2D) << "STRIDE_W: " << param.stride.horizontal << std::endl; + + VERBOSE(DepthwiseConv2D) << "ACTIVATION: " << param.activation << std::endl; + + VERBOSE(DepthwiseConv2D) << "PAD(T): " << param.padding.top << std::endl; + VERBOSE(DepthwiseConv2D) << "PAD(B): " << param.padding.bottom << std::endl; + VERBOSE(DepthwiseConv2D) << "PAD(L): " << param.padding.left << std::endl; + VERBOSE(DepthwiseConv2D) << "PAD(R): " << param.padding.right << std::endl; + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index}); + auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index}); + auto ker_alloc = ctx.at(::internal::tflite::operand::Index{param.ker_index}); + auto bias_alloc = ctx.at(::internal::tflite::operand::Index{param.bias_index}); + + const auto conv_info = asPadStrideInfo(param.padding, param.stride); + + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLDepthwiseConvolutionLayer>(); + + fn->configure(CAST_CL(ifm_alloc), CAST_CL(ker_alloc), CAST_CL(bias_alloc), CAST_CL(ofm_alloc), + conv_info, param.multipler); + + builder.append("DepthwiseConv2D", std::move(fn)); + } + else + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::NEDepthwiseConvolutionLayer>(); + + fn->configure(ifm_alloc, ker_alloc, bias_alloc, ofm_alloc, conv_info, param.multipler); + + builder.append("DepthwiseConv2D", std::move(fn)); + } + + ActivationBuilder{builder}.append(param.activation, ofm_alloc); + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::DepthwiseConv2D::Explicit::Node &node) +{ + const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index}; + + const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index}; + const ::internal::tflite::operand::Index ker_index{node.param().ker_index}; + const ::internal::tflite::operand::Index bias_index{node.param().bias_index}; + + const ::internal::tflite::operand::Index vstride_index{node.param().vstride_index}; + const ::internal::tflite::operand::Index hstride_index{node.param().hstride_index}; + + const ::internal::tflite::operand::Index padding_left_index{node.param().padding_left_index}; + const ::internal::tflite::operand::Index padding_right_index{node.param().padding_right_index}; + const ::internal::tflite::operand::Index padding_top_index{node.param().padding_top_index}; + const ::internal::tflite::operand::Index padding_bottom_index{node.param().padding_bottom_index}; + + const ::internal::tflite::operand::Index multiplier_index{node.param().multiplier_index}; + const ::internal::tflite::operand::Index activation_index{node.param().activation_index}; + + const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(); + + const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(); + const auto ker_shape = _ctx.at(ker_index).shape().asFeature(); + const auto bias_size = _ctx.at(bias_index).shape().asVector(); + + auto multiplier = _ctx.at(multiplier_index).asScalar<int>(); + + assert(ker_shape.C == bias_size); + assert(ker_shape.C == ifm_shape.C * multiplier); + + const int32_t padding_left = _ctx.at(padding_left_index).asScalar<int32_t>(); + const int32_t padding_right = _ctx.at(padding_right_index).asScalar<int32_t>(); + const int32_t padding_top = _ctx.at(padding_top_index).asScalar<int32_t>(); + const int32_t padding_bottom = _ctx.at(padding_bottom_index).asScalar<int32_t>(); + + Stride stride; + + stride.vertical = _ctx.at(vstride_index).asScalar<int32_t>(); + stride.horizontal = _ctx.at(hstride_index).asScalar<int32_t>(); + + // TODO Should move to the place where the operand is handled, if it is possible. + // Set Shape Constraints and TensorInfo + _builder.addShapeConstr( + ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(), + _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint())); + _builder.addShapeConstr( + ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(), + _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint())); + // NOTE DepthwiseConv2D kernel is of shape [1, KER_W, KER_H, IFM_C * MULTIPLIER] + _builder.addShapeConstr( + ker_index, asTensorInfo(asTensorShape(_ctx.at(ker_index).shape()), _ctx.at(ker_index).type(), + _ctx.at(ker_index).scale(), _ctx.at(ker_index).zeroPoint())); + _builder.addShapeConstr(bias_index, + asTensorInfo(asTensorShape(_ctx.at(bias_index).shape()), + _ctx.at(bias_index).type(), _ctx.at(bias_index).scale(), + _ctx.at(bias_index).zeroPoint())); + + // Construct operation parameters + struct Param + { + int ofm_index; + int ifm_index; + int ker_index; + int bias_index; + + Padding padding; + Stride stride; + + int multipler; + FuseCode activation; + }; + + Param param; + + param.ofm_index = ofm_index.asInt(); + param.ifm_index = ifm_index.asInt(); + param.ker_index = ker_index.asInt(); + param.bias_index = bias_index.asInt(); + + param.stride = stride; + + param.padding.left = padding_left; + param.padding.right = padding_right; + param.padding.top = padding_top; + param.padding.bottom = padding_bottom; + + param.multipler = multiplier; + param.activation = static_cast<FuseCode>(_ctx.at(activation_index).asScalar<int32_t>()); + + VERBOSE(DepthwiseConv2D) << "OFM_C: " << ofm_shape.C << std::endl; + VERBOSE(DepthwiseConv2D) << "OFM_H: " << ofm_shape.H << std::endl; + VERBOSE(DepthwiseConv2D) << "OFM_W: " << ofm_shape.W << std::endl; + + VERBOSE(DepthwiseConv2D) << "IFM_C: " << ifm_shape.C << std::endl; + VERBOSE(DepthwiseConv2D) << "IFM_H: " << ifm_shape.H << std::endl; + VERBOSE(DepthwiseConv2D) << "IFM_W: " << ifm_shape.W << std::endl; + + VERBOSE(DepthwiseConv2D) << "KER_C: " << ker_shape.C << std::endl; + VERBOSE(DepthwiseConv2D) << "KER_H: " << ker_shape.H << std::endl; + VERBOSE(DepthwiseConv2D) << "KER_W: " << ker_shape.W << std::endl; + + VERBOSE(DepthwiseConv2D) << "STRIDE_H: " << param.stride.vertical << std::endl; + VERBOSE(DepthwiseConv2D) << "STRIDE_W: " << param.stride.horizontal << std::endl; + + VERBOSE(DepthwiseConv2D) << "ACTIVATION: " << param.activation << std::endl; + + VERBOSE(DepthwiseConv2D) << "PAD(T): " << param.padding.top << std::endl; + VERBOSE(DepthwiseConv2D) << "PAD(B): " << param.padding.bottom << std::endl; + VERBOSE(DepthwiseConv2D) << "PAD(L): " << param.padding.left << std::endl; + VERBOSE(DepthwiseConv2D) << "PAD(R): " << param.padding.right << std::endl; + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index}); + auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index}); + auto ker_alloc = ctx.at(::internal::tflite::operand::Index{param.ker_index}); + auto bias_alloc = ctx.at(::internal::tflite::operand::Index{param.bias_index}); + + const auto conv_info = asPadStrideInfo(param.padding, param.stride); + + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLDepthwiseConvolutionLayer>(); + + fn->configure(CAST_CL(ifm_alloc), CAST_CL(ker_alloc), CAST_CL(bias_alloc), CAST_CL(ofm_alloc), + conv_info, param.multipler); + + builder.append("DepthwiseConv2D", std::move(fn)); + } + else + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::NEDepthwiseConvolutionLayer>(); + + fn->configure(ifm_alloc, ker_alloc, bias_alloc, ofm_alloc, conv_info, param.multipler); + + builder.append("DepthwiseConv2D", std::move(fn)); + } + + ActivationBuilder{builder}.append(param.activation, ofm_alloc); + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::Dequantize::Node &node) +{ + const ::internal::tflite::operand::Index output_index{node.param().output_index}; + const ::internal::tflite::operand::Index input_index{node.param().input_index}; + + assert(_ctx.at(input_index).shape().rank() >= 0 && _ctx.at(input_index).shape().rank() <= 4); + assert(_ctx.at(input_index).shape() == _ctx.at(output_index).shape()); + assert(_ctx.at(input_index).type() == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM); + assert(_ctx.at(output_index).type() == ANEURALNETWORKS_TENSOR_FLOAT32); + + // Set Shape Constraints + _builder.addShapeConstr(output_index, + asTensorInfo(asTensorShape(_ctx.at(output_index).shape()), + _ctx.at(output_index).type(), _ctx.at(output_index).scale(), + _ctx.at(output_index).zeroPoint())); + _builder.addShapeConstr(input_index, + asTensorInfo(asTensorShape(_ctx.at(input_index).shape()), + _ctx.at(input_index).type(), _ctx.at(input_index).scale(), + _ctx.at(input_index).zeroPoint())); + + // Construct operation parameters + struct Param + { + int output_index; + int input_index; + }; + + Param param; + + param.output_index = output_index.asInt(); + param.input_index = input_index.asInt(); + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.output_index}); + auto input_alloc = ctx.at(::internal::tflite::operand::Index{param.input_index}); + + std::unique_ptr<::arm_compute::IFunction> fn; + + { + if (::internal::arm_compute::isGpuMode()) + { + auto l = nnfw::cpp14::make_unique<::arm_compute::CLCast>(); + + l->configure(CAST_CL(input_alloc), CAST_CL(output_alloc)); + fn = std::move(l); + } + else + throw std::runtime_error("Not supported, yet"); + } + + builder.append("Dequantize", std::move(fn)); + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::MaxPool2D::Implicit::Node &node) +{ + const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index}; + const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index}; + + const ::internal::tflite::operand::Index kh_index{node.param().kh_index}; + const ::internal::tflite::operand::Index kw_index{node.param().kw_index}; + + const ::internal::tflite::operand::Index vstride_index{node.param().vstride_index}; + const ::internal::tflite::operand::Index hstride_index{node.param().hstride_index}; + + const ::internal::tflite::operand::Index padding_index{node.param().padding_index}; + const ::internal::tflite::operand::Index activation_index{node.param().activation_index}; + + const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(); + const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(); + + const int32_t kh = _ctx.at(kh_index).asScalar<int32_t>(); + const int32_t kw = _ctx.at(kw_index).asScalar<int32_t>(); + + const int32_t vstride = _ctx.at(vstride_index).asScalar<int32_t>(); + const int32_t hstride = _ctx.at(hstride_index).asScalar<int32_t>(); + + const PaddingCode padding_type = + static_cast<PaddingCode>(_ctx.at(padding_index).asScalar<int32_t>()); + + assert((ANEURALNETWORKS_PADDING_SAME == padding_type) || + (ANEURALNETWORKS_PADDING_VALID == padding_type)); + + // TODO Should move to the place where the operand is handled, if it is possible. + // Set Shape Constraints and TensorInfo + _builder.addShapeConstr( + ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(), + _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint())); + _builder.addShapeConstr( + ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(), + _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint())); + + // Construct operation parameters + struct Param + { + int ofm_index; + int ifm_index; + + uint32_t kw; + uint32_t kh; + + Padding padding; + Stride stride; + + FuseCode activation; + }; + + Param param; + + param.ofm_index = ofm_index.asInt(); + param.ifm_index = ifm_index.asInt(); + + param.kh = kh; + param.kw = kw; + + param.stride.vertical = vstride; + param.stride.horizontal = hstride; + + param.padding = (padding_type == ANEURALNETWORKS_PADDING_SAME) + ? same_padding(ifm_shape, ofm_shape, param.stride, kw, kh) + : valid_padding(); + param.activation = static_cast<FuseCode>(_ctx.at(activation_index).asScalar<int32_t>()); + + VERBOSE(MaxPool2D) << "IFM_H: " << ifm_shape.H << std::endl; + VERBOSE(MaxPool2D) << "IFM_W: " << ifm_shape.W << std::endl; + VERBOSE(MaxPool2D) << "OFM_H: " << ofm_shape.H << std::endl; + VERBOSE(MaxPool2D) << "OFM_W: " << ofm_shape.W << std::endl; + VERBOSE(MaxPool2D) << "KER_H: " << kh << std::endl; + VERBOSE(MaxPool2D) << "KER_W: " << kw << std::endl; + VERBOSE(MaxPool2D) << "STRIDE_H: " << vstride << std::endl; + VERBOSE(MaxPool2D) << "STRIDE_W: " << hstride << std::endl; + VERBOSE(MaxPool2D) << "PAD(T): " << param.padding.top << std::endl; + VERBOSE(MaxPool2D) << "PAD(B): " << param.padding.bottom << std::endl; + VERBOSE(MaxPool2D) << "PAD(L): " << param.padding.left << std::endl; + VERBOSE(MaxPool2D) << "PAD(R): " << param.padding.right << std::endl; + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index}); + auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index}); + + ::arm_compute::PoolingLayerInfo info{::arm_compute::PoolingType::MAX, + ::arm_compute::Size2D{param.kw, param.kh}, + asPadStrideInfo(param.padding, param.stride)}; + + if (::internal::arm_compute::isGpuMode()) + { + std::unique_ptr<::arm_compute::CLPoolingLayer> fn{new ::arm_compute::CLPoolingLayer}; + + fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc), info); + + builder.append("MaxPool2D", std::move(fn)); + } + else + { + std::unique_ptr<::arm_compute::NEPoolingLayer> fn{new ::arm_compute::NEPoolingLayer}; + + fn->configure(ifm_alloc, ofm_alloc, info); + + builder.append("MaxPool2D", std::move(fn)); + } + + ActivationBuilder{builder}.append(param.activation, ofm_alloc); + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::MaxPool2D::Explicit::Node &node) +{ + const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index}; + const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index}; + + const ::internal::tflite::operand::Index kh_index{node.param().kh_index}; + const ::internal::tflite::operand::Index kw_index{node.param().kw_index}; + + const ::internal::tflite::operand::Index vstride_index{node.param().vstride_index}; + const ::internal::tflite::operand::Index hstride_index{node.param().hstride_index}; + + const ::internal::tflite::operand::Index padding_left_index{node.param().padding_left_index}; + const ::internal::tflite::operand::Index padding_right_index{node.param().padding_right_index}; + const ::internal::tflite::operand::Index padding_top_index{node.param().padding_top_index}; + const ::internal::tflite::operand::Index padding_bottom_index{node.param().padding_bottom_index}; + + const ::internal::tflite::operand::Index activation_index{node.param().activation_index}; + + const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(); + const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(); + + const int32_t kh = _ctx.at(kh_index).asScalar<int32_t>(); + const int32_t kw = _ctx.at(kw_index).asScalar<int32_t>(); + + const int32_t vstride = _ctx.at(vstride_index).asScalar<int32_t>(); + const int32_t hstride = _ctx.at(hstride_index).asScalar<int32_t>(); + + const int32_t padding_left = _ctx.at(padding_left_index).asScalar<int32_t>(); + const int32_t padding_right = _ctx.at(padding_right_index).asScalar<int32_t>(); + const int32_t padding_top = _ctx.at(padding_top_index).asScalar<int32_t>(); + const int32_t padding_bottom = _ctx.at(padding_bottom_index).asScalar<int32_t>(); + + // TODO Should move to the place where the operand is handled, if it is possible. + // Set Shape Constraints and TensorInfo + _builder.addShapeConstr( + ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(), + _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint())); + _builder.addShapeConstr( + ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(), + _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint())); + + // Construct operation parameters + struct Param + { + int ofm_index; + int ifm_index; + + uint32_t kw; + uint32_t kh; + + Padding padding; + Stride stride; + + FuseCode activation; + }; + + Param param; + + param.ofm_index = ofm_index.asInt(); + param.ifm_index = ifm_index.asInt(); + + param.kh = kh; + param.kw = kw; + + param.stride.vertical = vstride; + param.stride.horizontal = hstride; + + param.padding.left = padding_left; + param.padding.right = padding_right; + param.padding.top = padding_top; + param.padding.bottom = padding_bottom; + + param.activation = static_cast<FuseCode>(_ctx.at(activation_index).asScalar<int32_t>()); + + VERBOSE(MaxPool2D) << "IFM_H: " << ifm_shape.H << std::endl; + VERBOSE(MaxPool2D) << "IFM_W: " << ifm_shape.W << std::endl; + VERBOSE(MaxPool2D) << "OFM_H: " << ofm_shape.H << std::endl; + VERBOSE(MaxPool2D) << "OFM_W: " << ofm_shape.W << std::endl; + VERBOSE(MaxPool2D) << "KER_H: " << kh << std::endl; + VERBOSE(MaxPool2D) << "KER_W: " << kw << std::endl; + VERBOSE(MaxPool2D) << "STRIDE_H: " << vstride << std::endl; + VERBOSE(MaxPool2D) << "STRIDE_W: " << hstride << std::endl; + VERBOSE(MaxPool2D) << "PAD(T): " << param.padding.top << std::endl; + VERBOSE(MaxPool2D) << "PAD(B): " << param.padding.bottom << std::endl; + VERBOSE(MaxPool2D) << "PAD(L): " << param.padding.left << std::endl; + VERBOSE(MaxPool2D) << "PAD(R): " << param.padding.right << std::endl; + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index}); + auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index}); + + ::arm_compute::PoolingLayerInfo info{::arm_compute::PoolingType::MAX, + ::arm_compute::Size2D{param.kw, param.kh}, + asPadStrideInfo(param.padding, param.stride)}; + + if (::internal::arm_compute::isGpuMode()) + { + std::unique_ptr<::arm_compute::CLPoolingLayer> fn{new ::arm_compute::CLPoolingLayer}; + + fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc), info); + + builder.append("MaxPool2D", std::move(fn)); + } + else + { + std::unique_ptr<::arm_compute::NEPoolingLayer> fn{new ::arm_compute::NEPoolingLayer}; + + fn->configure(ifm_alloc, ofm_alloc, info); + + builder.append("MaxPool2D", std::move(fn)); + } + + ActivationBuilder{builder}.append(param.activation, ofm_alloc); + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::AvgPool2D::Implicit::Node &node) +{ + const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index}; + const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index}; + + const ::internal::tflite::operand::Index kh_index{node.param().kh_index}; + const ::internal::tflite::operand::Index kw_index{node.param().kw_index}; + + const ::internal::tflite::operand::Index vstride_index{node.param().vstride_index}; + const ::internal::tflite::operand::Index hstride_index{node.param().hstride_index}; + + const ::internal::tflite::operand::Index padding_index{node.param().padding_index}; + const ::internal::tflite::operand::Index activation_index{node.param().activation_index}; + + const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(); + const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(); + + const int32_t kh = _ctx.at(kh_index).asScalar<int32_t>(); + const int32_t kw = _ctx.at(kw_index).asScalar<int32_t>(); + + const int32_t vstride = _ctx.at(vstride_index).asScalar<int32_t>(); + const int32_t hstride = _ctx.at(hstride_index).asScalar<int32_t>(); + + const PaddingCode padding_type = + static_cast<PaddingCode>(_ctx.at(padding_index).asScalar<int32_t>()); + + assert((ANEURALNETWORKS_PADDING_SAME == padding_type) || + (ANEURALNETWORKS_PADDING_VALID == padding_type)); + + // TODO Should move to the place where the operand is handled, if it is possible. + // Set Shape Constraints and TensorInfo + _builder.addShapeConstr( + ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(), + _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint())); + _builder.addShapeConstr( + ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(), + _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint())); + + // Construct operation parameters + struct Param + { + int ofm_index; + int ifm_index; + + uint32_t kw; + uint32_t kh; + + Padding padding; + Stride stride; + + FuseCode activation; + }; + + Param param; + + param.ofm_index = ofm_index.asInt(); + param.ifm_index = ifm_index.asInt(); + + param.kh = kh; + param.kw = kw; + + param.stride.vertical = vstride; + param.stride.horizontal = hstride; + + param.padding = (padding_type == ANEURALNETWORKS_PADDING_SAME) + ? same_padding(ifm_shape, ofm_shape, param.stride, kw, kh) + : valid_padding(); + + param.activation = static_cast<FuseCode>(_ctx.at(activation_index).asScalar<int32_t>()); + + VERBOSE(AvgPool2D) << "IFM_H: " << ifm_shape.H << std::endl; + VERBOSE(AvgPool2D) << "IFM_W: " << ifm_shape.W << std::endl; + VERBOSE(AvgPool2D) << "OFM_H: " << ofm_shape.H << std::endl; + VERBOSE(AvgPool2D) << "OFM_W: " << ofm_shape.W << std::endl; + VERBOSE(AvgPool2D) << "KER_H: " << kh << std::endl; + VERBOSE(AvgPool2D) << "KER_W: " << kw << std::endl; + VERBOSE(AvgPool2D) << "STRIDE_H: " << vstride << std::endl; + VERBOSE(AvgPool2D) << "STRIDE_W: " << hstride << std::endl; + VERBOSE(AvgPool2D) << "PAD: " << to_string(padding_type) << std::endl; + VERBOSE(AvgPool2D) << "PAD(T): " << param.padding.top << std::endl; + VERBOSE(AvgPool2D) << "PAD(B): " << param.padding.bottom << std::endl; + VERBOSE(AvgPool2D) << "PAD(L): " << param.padding.left << std::endl; + VERBOSE(AvgPool2D) << "PAD(R): " << param.padding.right << std::endl; + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index}); + auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index}); + + ::arm_compute::PoolingLayerInfo info{ + ::arm_compute::PoolingType::AVG, ::arm_compute::Size2D{param.kw, param.kh}, + asPadStrideInfo(param.padding, param.stride), true /* exclude_padding */}; + + if (::internal::arm_compute::isGpuMode()) + { + std::unique_ptr<::arm_compute::CLPoolingLayer> fn{new ::arm_compute::CLPoolingLayer}; + + fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc), info); + + builder.append("AvgPool2D", std::move(fn)); + } + else + { + std::unique_ptr<::arm_compute::NEPoolingLayer> fn{new ::arm_compute::NEPoolingLayer}; + + fn->configure(ifm_alloc, ofm_alloc, info); + + builder.append("AvgPool2D", std::move(fn)); + } + + ActivationBuilder{builder}.append(param.activation, ofm_alloc); + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::AvgPool2D::Explicit::Node &node) +{ + const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index}; + const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index}; + + const ::internal::tflite::operand::Index kh_index{node.param().kh_index}; + const ::internal::tflite::operand::Index kw_index{node.param().kw_index}; + + const ::internal::tflite::operand::Index vstride_index{node.param().vstride_index}; + const ::internal::tflite::operand::Index hstride_index{node.param().hstride_index}; + + const ::internal::tflite::operand::Index padding_left_index{node.param().padding_left_index}; + const ::internal::tflite::operand::Index padding_right_index{node.param().padding_right_index}; + const ::internal::tflite::operand::Index padding_top_index{node.param().padding_top_index}; + const ::internal::tflite::operand::Index padding_bottom_index{node.param().padding_bottom_index}; + + const ::internal::tflite::operand::Index activation_index{node.param().activation_index}; + + const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(); + const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(); + + const int32_t kh = _ctx.at(kh_index).asScalar<int32_t>(); + const int32_t kw = _ctx.at(kw_index).asScalar<int32_t>(); + + const int32_t vstride = _ctx.at(vstride_index).asScalar<int32_t>(); + const int32_t hstride = _ctx.at(hstride_index).asScalar<int32_t>(); + + const int32_t padding_left = _ctx.at(padding_left_index).asScalar<int32_t>(); + const int32_t padding_right = _ctx.at(padding_right_index).asScalar<int32_t>(); + const int32_t padding_top = _ctx.at(padding_top_index).asScalar<int32_t>(); + const int32_t padding_bottom = _ctx.at(padding_bottom_index).asScalar<int32_t>(); + + // TODO Should move to the place where the operand is handled, if it is possible. + // Set Shape Constraints and TensorInfo + _builder.addShapeConstr( + ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(), + _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint())); + _builder.addShapeConstr( + ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(), + _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint())); + + // Construct operation parameters + struct Param + { + int ofm_index; + int ifm_index; + + uint32_t kw; + uint32_t kh; + + Padding padding; + Stride stride; + + FuseCode activation; + }; + + Param param; + + param.ofm_index = ofm_index.asInt(); + param.ifm_index = ifm_index.asInt(); + + param.kh = kh; + param.kw = kw; + + param.stride.vertical = vstride; + param.stride.horizontal = hstride; + + param.padding.left = padding_left; + param.padding.right = padding_right; + param.padding.top = padding_top; + param.padding.bottom = padding_bottom; + + param.activation = static_cast<FuseCode>(_ctx.at(activation_index).asScalar<int32_t>()); + + VERBOSE(AvgPool2D) << "IFM_H: " << ifm_shape.H << std::endl; + VERBOSE(AvgPool2D) << "IFM_W: " << ifm_shape.W << std::endl; + VERBOSE(AvgPool2D) << "OFM_H: " << ofm_shape.H << std::endl; + VERBOSE(AvgPool2D) << "OFM_W: " << ofm_shape.W << std::endl; + VERBOSE(AvgPool2D) << "KER_H: " << kh << std::endl; + VERBOSE(AvgPool2D) << "KER_W: " << kw << std::endl; + VERBOSE(AvgPool2D) << "STRIDE_H: " << vstride << std::endl; + VERBOSE(AvgPool2D) << "STRIDE_W: " << hstride << std::endl; + VERBOSE(AvgPool2D) << "PAD(T): " << param.padding.top << std::endl; + VERBOSE(AvgPool2D) << "PAD(B): " << param.padding.bottom << std::endl; + VERBOSE(AvgPool2D) << "PAD(L): " << param.padding.left << std::endl; + VERBOSE(AvgPool2D) << "PAD(R): " << param.padding.right << std::endl; + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index}); + auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index}); + + ::arm_compute::PoolingLayerInfo info{ + ::arm_compute::PoolingType::AVG, ::arm_compute::Size2D{param.kw, param.kh}, + asPadStrideInfo(param.padding, param.stride), true /* exclude_padding */}; + + if (::internal::arm_compute::isGpuMode()) + { + std::unique_ptr<::arm_compute::CLPoolingLayer> fn{new ::arm_compute::CLPoolingLayer}; + + fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc), info); + + builder.append("AvgPool2D", std::move(fn)); + } + else + { + std::unique_ptr<::arm_compute::NEPoolingLayer> fn{new ::arm_compute::NEPoolingLayer}; + + fn->configure(ifm_alloc, ofm_alloc, info); + + builder.append("AvgPool2D", std::move(fn)); + } + + ActivationBuilder{builder}.append(param.activation, ofm_alloc); + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::Concat::Node &node) +{ + const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index}; + const ::internal::tflite::operand::Index axis_index{node.param().axis_index}; + + // NOTE This implementation assumes that inputs and output are a feature + const auto ofm_shape = _ctx.at(ofm_index).shape(); + uint32_t input_rank = ofm_shape.rank(); + int32_t axis = _ctx.at(axis_index).asScalar<int32_t>(); + + // Handle negative axis + if (axis < 0) + { + axis += input_rank; + } + + // Set Shape Constraints and TensorInfo (for output) + _builder.addShapeConstr( + ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(), + _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint())); + + // Set Shape Constraints and TensorInfo (for input) + const uint32_t coord_index = ToARMComputeAxis(input_rank, axis).value(); + uint32_t depth = 0; + + ::arm_compute::Coordinates coordinates; + coordinates.set_num_dimensions(input_rank); + + for (const auto &index : node.param().ifm_indexes) + { + const ::internal::tflite::operand::Index ifm_index{index}; + const auto ifm_shape = _ctx.at(ifm_index).shape(); + + coordinates[coord_index] = depth; + + _builder.addSubsumptionConstr(ifm_index, ofm_index, coordinates, + asTensorShape(_ctx.at(ifm_index).shape()), true); + + depth += ifm_shape.dim(axis); + } + + // NOTE Concat has no actual operation! + // However, dummy stage is added because profiler assumes every operation make a stage. + auto stage = [](const IAllocationContext &ctx, IExecutionBuilder &builder) {}; + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::FullyConnected::Node &node) +{ + VERBOSE(FullyConnected) << "Configure FULLY_CONNECTED operation" << std::endl; + + const ::internal::tflite::operand::Index output_index{node.param().output_index}; + + const ::internal::tflite::operand::Index input_index{node.param().input_index}; + const ::internal::tflite::operand::Index weight_index{node.param().weight_index}; + const ::internal::tflite::operand::Index bias_index{node.param().bias_index}; + + const ::internal::tflite::operand::Index activation_index{node.param().activation_index}; + + assert(_ctx.at(input_index).shape().rank() >= 2); + assert(_ctx.at(output_index).shape().rank() == 2); + assert(_ctx.at(weight_index).shape().rank() == 2); + assert(_ctx.at(bias_index).shape().rank() == 1); + + const auto input_rank = _ctx.at(input_index).shape().rank(); + // TODO Currently we are not handling where the case is that the input's rank is 3. + // The handling should be added in the future. + assert(input_rank != 3); + + const auto output_size = _ctx.at(output_index).shape().dim(1); + assert(_ctx.at(bias_index).shape().dim(0) == output_size); + assert(_ctx.at(weight_index).shape().dim(0) == output_size); + const auto batch_size = _ctx.at(output_index).shape().dim(0); + const auto input_size = _ctx.at(weight_index).shape().dim(1); + + // Check for reshaping input's shape into rank-2 + bool needs_reshape = false; + internal::tflite::operand::Shape reshape(2); + if (input_rank == 4) + { + nnfw::misc::feature::Shape ifm_shape_feature = _ctx.at(input_index).shape().asFeature(); + auto feature_size = + ifm_shape_feature.N * ifm_shape_feature.C * ifm_shape_feature.H * ifm_shape_feature.W; + assert(feature_size == batch_size * input_size); + + _builder.addShapeConstr(input_index, + asTensorInfo(asTensorShape(_ctx.at(input_index).shape(), false), + _ctx.at(input_index).type(), _ctx.at(input_index).scale(), + _ctx.at(input_index).zeroPoint())); + + // for reshaping + needs_reshape = true; + reshape.dim(0) = batch_size; /* H */ + reshape.dim(1) = input_size; /* W */ + } + else if (input_rank == 2) + { + auto ifm_shape = _ctx.at(input_index).shape(); + nnfw::misc::matrix::Shape ifm_shape_matrix = ifm_shape.asMatrix(); + assert(ifm_shape.dim(0) == batch_size); + assert(ifm_shape.dim(1) == input_size); + + _builder.addShapeConstr(input_index, + asTensorInfo(asTensorShape(_ctx.at(input_index).shape()), + _ctx.at(input_index).type(), _ctx.at(input_index).scale(), + _ctx.at(input_index).zeroPoint())); + } + + // TODO Should move to the place where the operand is handled, if it is possible. + // Set Shape Constraints + _builder.addShapeConstr(output_index, + asTensorInfo(asTensorShape(_ctx.at(output_index).shape()), + _ctx.at(output_index).type(), _ctx.at(output_index).scale(), + _ctx.at(output_index).zeroPoint())); + _builder.addShapeConstr(weight_index, + asTensorInfo(asTensorShape(_ctx.at(weight_index).shape()), + _ctx.at(weight_index).type(), _ctx.at(weight_index).scale(), + _ctx.at(weight_index).zeroPoint())); + _builder.addShapeConstr(bias_index, + asTensorInfo(asTensorShape(_ctx.at(bias_index).shape()), + _ctx.at(bias_index).type(), _ctx.at(bias_index).scale(), + _ctx.at(bias_index).zeroPoint())); + + // Construct operation parameters + struct Param + { + int output_index; + + int input_index; + int weight_index; + int bias_index; + + FuseCode activation; + }; + + Param param; + + param.output_index = output_index.asInt(); + param.input_index = input_index.asInt(); + param.weight_index = weight_index.asInt(); + param.bias_index = bias_index.asInt(); + + param.activation = static_cast<FuseCode>(_ctx.at(activation_index).asScalar<int32_t>()); + + auto stage = [param, needs_reshape, reshape](const IAllocationContext &ctx, + IExecutionBuilder &builder) { + auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.output_index}); + auto input_alloc = ctx.at(::internal::tflite::operand::Index{param.input_index}); + auto weight_alloc = ctx.at(::internal::tflite::operand::Index{param.weight_index}); + auto bias_alloc = ctx.at(::internal::tflite::operand::Index{param.bias_index}); + + auto fn = nnfw::cpp14::make_unique<arm_compute::CLFullyConnectedReshapingLayer>(); + + fn->configure(CAST_CL(input_alloc), CAST_CL(weight_alloc), CAST_CL(bias_alloc), + CAST_CL(output_alloc), needs_reshape, asTensorShape(reshape)); + + builder.append("FullyConnected", std::move(fn)); + + ActivationBuilder{builder}.append(param.activation, output_alloc); + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::ResizeBilinear::Node &node) +{ + const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index}; + + const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index}; + const ::internal::tflite::operand::Index height_index{node.param().height_index}; + const ::internal::tflite::operand::Index width_index{node.param().width_index}; + + // TODO Should move to the place where the operand is handled, if it is possible. + // Set Shape Constraints + _builder.addShapeConstr( + ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(), + _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint())); + _builder.addShapeConstr( + ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(), + _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint())); + + struct Param + { + int ofm_index; + int ifm_index; + + int new_height; + int new_width; + }; + + Param param; + + param.ofm_index = ofm_index.asInt(); + param.ifm_index = ifm_index.asInt(); + param.new_height = _ctx.at(height_index).asScalar<int32_t>(); + param.new_width = _ctx.at(width_index).asScalar<int32_t>(); + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index}); + auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index}); + + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLScale>(); + + fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc), + ::arm_compute::InterpolationPolicy::BILINEAR, + ::arm_compute::BorderMode::REPLICATE, ::arm_compute::PixelValue(0.f), + ::arm_compute::SamplingPolicy::TOP_LEFT); + + builder.append("ResizeBilinear", std::move(fn)); + } + else + throw std::runtime_error("Not supported, yet"); + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::Reshape::Node &node) +{ + const ::internal::tflite::operand::Index output_index{node.param().output_index}; + const ::internal::tflite::operand::Index input_index{node.param().input_index}; + + auto input_shape = asTensorShape(_ctx.at(input_index).shape(), false); + auto output_shape = asTensorShape(_ctx.at(output_index).shape(), false); + + assert(input_shape[0] * input_shape[1] * input_shape[2] * input_shape[3] == + output_shape[0] * output_shape[1] * output_shape[2] * output_shape[3]); + + // TODO Should move to the place where the operand is handled, if it is possible. + _builder.addShapeConstr(output_index, asTensorInfo(output_shape, _ctx.at(output_index).type(), + _ctx.at(output_index).scale(), + _ctx.at(output_index).zeroPoint())); + _builder.addShapeConstr(input_index, asTensorInfo(input_shape, _ctx.at(input_index).type(), + _ctx.at(input_index).scale(), + _ctx.at(input_index).zeroPoint())); + + struct Param + { + int output_index; + int input_index; + }; + + Param param; + + param.output_index = output_index.asInt(); + param.input_index = input_index.asInt(); + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.output_index}); + auto input_alloc = ctx.at(::internal::tflite::operand::Index{param.input_index}); + + if (::internal::arm_compute::isGpuMode()) + { + // GenericReshape first apply NCHW->NHWC permutation, and apply reshape + auto fn = nnfw::cpp14::make_unique<GenericReshapeLayer>(); + + fn->configure(CAST_CL(input_alloc), CAST_CL(output_alloc)); + + builder.append("Reshape", std::move(fn)); + } + else + { + auto fn = nnfw::cpp14::make_unique<GenericReshapeLayer>(); + + fn->configure(input_alloc, output_alloc); + + builder.append("Reshape", std::move(fn)); + } + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::Squeeze::Node &node) +{ + // node.param().dims_index_optional is ignored since output tensor already has squeezed shape + // by freezer and toco + const ::internal::tflite::operand::Index output_index{node.param().output_index}; + const ::internal::tflite::operand::Index input_index{node.param().input_index}; + + // Set Shape Constraints + _builder.addShapeConstr(output_index, + asTensorInfo(asTensorShape(_ctx.at(output_index).shape()), + _ctx.at(output_index).type(), _ctx.at(output_index).scale(), + _ctx.at(output_index).zeroPoint())); + _builder.addShapeConstr(input_index, + asTensorInfo(asTensorShape(_ctx.at(input_index).shape()), + _ctx.at(input_index).type(), _ctx.at(input_index).scale(), + _ctx.at(input_index).zeroPoint())); + + // Construct operation parameters + struct Param + { + int output_index; + int input_index; + }; + + Param param; + + param.output_index = output_index.asInt(); + param.input_index = input_index.asInt(); + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.output_index}); + auto input_alloc = ctx.at(::internal::tflite::operand::Index{param.input_index}); + + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLReshapeLayer>(); + + fn->configure(CAST_CL(input_alloc), CAST_CL(output_alloc)); + + builder.append("Squeeze", std::move(fn)); + } + else + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::NEReshapeLayer>(); + + fn->configure(input_alloc, output_alloc); + + builder.append("Squeeze", std::move(fn)); + } + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::Softmax::Node &node) +{ + VERBOSE(Softmax) << "Configure SOFTMAX operation" << std::endl; + + const ::internal::tflite::operand::Index output_index{node.param().output_index}; + const ::internal::tflite::operand::Index input_index{node.param().input_index}; + const ::internal::tflite::operand::Index scale_index{node.param().scale_index}; + + assert(_ctx.at(output_index).shape().rank() == _ctx.at(input_index).shape().rank()); + assert(_ctx.at(scale_index).shape().rank() == 0); + + // TODO Should move to the place where the operand is handled, if it is possible. + _builder.addShapeConstr(output_index, + asTensorInfo(asTensorShape(_ctx.at(output_index).shape()), + _ctx.at(output_index).type(), _ctx.at(output_index).scale(), + _ctx.at(output_index).zeroPoint())); + _builder.addShapeConstr(input_index, + asTensorInfo(asTensorShape(_ctx.at(input_index).shape()), + _ctx.at(input_index).type(), _ctx.at(input_index).scale(), + _ctx.at(input_index).zeroPoint())); + + struct Param + { + int output_index; + int input_index; + float scale; + }; + + Param param; + + param.output_index = output_index.asInt(); + param.input_index = input_index.asInt(); + param.scale = _ctx.at(scale_index).asScalar<float>(); + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.output_index}); + auto input_alloc = ctx.at(::internal::tflite::operand::Index{param.input_index}); + + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLSoftmaxLayer>(); + + fn->configure(CAST_CL(input_alloc), CAST_CL(output_alloc), param.scale); + + builder.append("Softmax", std::move(fn)); + } + else + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::NESoftmaxLayer>(); + + fn->configure(input_alloc, output_alloc, param.scale); + + builder.append("Softmax", std::move(fn)); + } + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::StridedSlice::Node &node) +{ + VERBOSE(StridedSlice) << "Configure STRIDED_SLICE operation" << std::endl; + + const ::internal::tflite::operand::Index outputData_index{node.param().outputData_index}; + + const ::internal::tflite::operand::Index inputData_index{node.param().inputData_index}; + const ::internal::tflite::operand::Index startData_index{node.param().startData_index}; + const ::internal::tflite::operand::Index endData_index{node.param().endData_index}; + const ::internal::tflite::operand::Index stridesData_index{node.param().stridesData_index}; + const ::internal::tflite::operand::Index beginMask_index{node.param().beginMask_index}; + const ::internal::tflite::operand::Index endMask_index{node.param().endMask_index}; + const ::internal::tflite::operand::Index shrinkAxisMask_index{node.param().shrinkAxisMask_index}; + + // Set Shape Constraints + _builder.addShapeConstr(outputData_index, + asTensorInfo(asTensorShape(_ctx.at(outputData_index).shape()), + _ctx.at(outputData_index).type(), + _ctx.at(outputData_index).scale(), + _ctx.at(outputData_index).zeroPoint())); + _builder.addShapeConstr( + inputData_index, + asTensorInfo(asTensorShape(_ctx.at(inputData_index).shape()), _ctx.at(inputData_index).type(), + _ctx.at(inputData_index).scale(), _ctx.at(inputData_index).zeroPoint())); + + assert(_ctx.at(startData_index).shape().rank() == 1); + assert(_ctx.at(endData_index).shape().rank() == 1); + assert(_ctx.at(stridesData_index).shape().rank() == 1); + _builder.addShapeConstr( + startData_index, + asTensorInfo(asTensorShape(_ctx.at(startData_index).shape()), _ctx.at(startData_index).type(), + _ctx.at(startData_index).scale(), _ctx.at(startData_index).zeroPoint())); + _builder.addShapeConstr(endData_index, asTensorInfo(asTensorShape(_ctx.at(endData_index).shape()), + _ctx.at(endData_index).type(), + _ctx.at(endData_index).scale(), + _ctx.at(endData_index).zeroPoint())); + _builder.addShapeConstr( + stridesData_index, + asTensorInfo(asTensorShape(_ctx.at(endData_index).shape()), _ctx.at(stridesData_index).type(), + _ctx.at(stridesData_index).scale(), _ctx.at(stridesData_index).zeroPoint())); + + // Set initializers for indices data such as order of inputData + int input_rank = _ctx.at(inputData_index).shape().rank(); + std::vector<int32_t> starts; + std::vector<int32_t> ends; + std::vector<int32_t> strides; + starts.resize(input_rank, 0); + ends.resize(input_rank, 0); + strides.resize(input_rank, 0); + { + auto input_shape = _ctx.at(inputData_index).shape(); + auto startData_base = _ctx.at(startData_index).data().base(); + auto endData_base = _ctx.at(endData_index).data().base(); + auto stridesData_base = _ctx.at(stridesData_index).data().base(); + const auto startData_size = _ctx.at(startData_index).shape().asVector(); + const auto endData_size = _ctx.at(endData_index).shape().asVector(); + const auto stridesData_size = _ctx.at(stridesData_index).shape().asVector(); + + assert(_ctx.at(startData_index).type() == ANEURALNETWORKS_TENSOR_INT32); + assert(_ctx.at(endData_index).type() == ANEURALNETWORKS_TENSOR_INT32); + assert(_ctx.at(stridesData_index).type() == ANEURALNETWORKS_TENSOR_INT32); + assert(startData_size == input_rank); + assert(endData_size == input_rank); + assert(stridesData_size == input_rank); + + assert(startData_base != nullptr); + for (uint32_t n = 0; n < input_rank; ++n) + { + auto axis = ToARMComputeAxis(input_rank, n).value(); + + int32_t start_value = *(reinterpret_cast<const int32_t *>(startData_base) + n); + starts[axis] = start_value; + + int32_t end_value = *(reinterpret_cast<const int32_t *>(endData_base) + n); + ends[axis] = end_value; + + int32_t strides_value = *(reinterpret_cast<const int32_t *>(stridesData_base) + n); + strides[axis] = strides_value; + } + } + + struct Param + { + int32_t outputData_index; + int32_t inputData_index; + + std::vector<int32_t> starts; + std::vector<int32_t> ends; + std::vector<int32_t> strides; + + int32_t beginMask; + int32_t endMask; + int32_t shrinkAxisMask; + }; + + Param param; + param.outputData_index = outputData_index.asInt(); + param.inputData_index = inputData_index.asInt(); + + param.starts = starts; + param.ends = ends; + param.strides = strides; + + // Set mask bits such as order of inputData + param.beginMask = _ctx.at(beginMask_index).asReorderBits<int32_t>(input_rank); + param.endMask = _ctx.at(endMask_index).asReorderBits<int32_t>(input_rank); + param.shrinkAxisMask = _ctx.at(shrinkAxisMask_index).asReorderBits<int32_t>(input_rank); + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto outputData_alloc = ctx.at(::internal::tflite::operand::Index{param.outputData_index}); + auto inputData_alloc = ctx.at(::internal::tflite::operand::Index{param.inputData_index}); + + ::arm_compute::Coordinates starts; + ::arm_compute::Coordinates ends; + ::arm_compute::BiStrides strides; + for (int i = 0; i < param.starts.size(); ++i) + { + starts.set(i, param.starts[i]); + ends.set(i, param.ends[i]); + strides.set(i, param.strides[i]); + } + + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLStridedSlice>(); + + fn->configure(CAST_CL(inputData_alloc), CAST_CL(outputData_alloc), starts, ends, strides, + param.beginMask, param.endMask, param.shrinkAxisMask); + + builder.append("StridedSlice", std::move(fn)); + } + else + throw std::runtime_error("Not supported, yet"); + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::ReduceMin::Node &node) +{ + VERBOSE(ReduceMin) << "Configure REDUCEMIN operation" << std::endl; + + const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index}; + const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index}; + const ::internal::tflite::operand::Index axis_index{node.param().axis_index}; + + auto ifm_shape = _ctx.at(ifm_index).shape(); + auto ofm_shape = _ctx.at(ofm_index).shape(); + auto axis_shape = _ctx.at(axis_index).shape(); + assert(ifm_shape.rank() <= 4); + assert(ofm_shape.rank() <= ifm_shape.rank()); + assert(_ctx.at(axis_index).hasData()); + assert(axis_shape.rank() == 0 || axis_shape.rank() == 1); + + // NOTE For the 4-dimensions, if the rank of input and output are different, this runtime only + // supports cases reducing height and width or reducing depth. + // TODO We have to support all cases of dimensions up to 4. + // For correct permuting, we have to set output's shape to be equal in dimension position of the + // input. But the positions of the same dimensions in the input and output may be set differently. + // For example {2,3,4,5}(input's shape) can be reduced to {3,5}(output's shape). The original + // output shape should be {1,3,1,5}, but real output shape may be {3,5}. If you simply try to + // extend it in 4 dimensions, it should be {1,1,3,5}. + // Even if output shape is changed to {1,3,1,5}, there is another problem. It is that shape of + // output tensor used at next operation is changed to {1,3,1,5} after this operation even if the + // next operation is not desired. + if (ifm_shape.rank() == 4 && ifm_shape.rank() != ofm_shape.rank()) + { + if (ofm_shape.rank() == 2) + { + // Reducing HW + assert(ifm_shape.dim(0) == ofm_shape.dim(0) && ifm_shape.dim(3) == ofm_shape.dim(1)); + } + else if (ofm_shape.rank() == 3) + { + // Reducing C or + // (Reducing H and C(ifm and ofm) == 1) or (Reducing W and C(ifm and ofm) == 1) + assert(ifm_shape.dim(0) == ofm_shape.dim(0) && ifm_shape.dim(1) == ofm_shape.dim(1) && + ifm_shape.dim(2) == ofm_shape.dim(2) || + (ifm_shape.dim(0) == ofm_shape.dim(0) && + (ifm_shape.dim(1) == ofm_shape.dim(1) || ifm_shape.dim(2) == ofm_shape.dim(1)) && + ifm_shape.dim(3) == 1 && ofm_shape.dim(2) == 1)); + } + } + + _builder.addShapeConstr( + ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(), + _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint())); + _builder.addShapeConstr( + ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(), + _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint())); + + std::set<uint32_t> axis; + { + const auto ifm_rank = ifm_shape.rank(); + switch (axis_shape.rank()) + { + case 0: // scalar + { + int32_t axis_value = _ctx.at(axis_index).asScalar<int32_t>(); + if (axis_value < 0) + { + axis_value += ifm_rank; + } + axis.insert(ToARMComputeAxis(ifm_rank, axis_value).value()); + break; + } + case 1: // vector + { + const auto axis_base = _ctx.at(axis_index).data().base(); + const auto axis_size = _ctx.at(axis_index).shape().asVector(); + + // If axis's data does not exist as constant values and can be gotten as input data, we have + // to find a way to infer output shape when sinking output. + assert(axis_base != nullptr); + for (uint32_t n = 0; n < axis_size; ++n) + { + int32_t axis_value = *(reinterpret_cast<const int32_t *>(axis_base) + n); + if (axis_value < 0) + { + axis_value += ifm_rank; + } + axis.insert(ToARMComputeAxis(ifm_rank, axis_value).value()); + } + break; + } + default: + throw std::runtime_error("Not supported"); + break; + } + } + + // Construct operation parameters + struct Param + { + int ofm_index; + int ifm_index; + std::set<uint32_t> axis; + }; + + Param param; + + param.ofm_index = ofm_index.asInt(); + param.ifm_index = ifm_index.asInt(); + param.axis = axis; + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index}); + auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index}); + + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLReduceOperation>(); + + fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc), param.axis, + ::arm_compute::ReduceOperation::MIN); + + builder.append("ReduceMin", std::move(fn)); + } + else + throw std::runtime_error("Not supported, yet"); + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::ReduceMax::Node &node) +{ + VERBOSE(ReduceMax) << "Configure REDUCEMAX operation" << std::endl; + + const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index}; + const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index}; + const ::internal::tflite::operand::Index axis_index{node.param().axis_index}; + + auto ifm_shape = _ctx.at(ifm_index).shape(); + auto ofm_shape = _ctx.at(ofm_index).shape(); + auto axis_shape = _ctx.at(axis_index).shape(); + assert(ifm_shape.rank() <= 4); + assert(ofm_shape.rank() <= ifm_shape.rank()); + assert(_ctx.at(axis_index).hasData()); + assert(axis_shape.rank() == 0 || axis_shape.rank() == 1); + + // NOTE For the 4-dimensions, if the rank of input and output are different, this runtime only + // supports cases reducing height and width or reducing depth. + // TODO We have to support all cases of dimensions up to 4. + // For correct permuting, we have to set output's shape to be equal in dimension position of the + // input. But the positions of the same dimensions in the input and output may be set differently. + // For example {2,3,4,5}(input's shape) can be reduced to {3,5}(output's shape). The original + // output shape should be {1,3,1,5}, but real output shape may be {3,5}. If you simply try to + // extend it in 4 dimensions, it should be {1,1,3,5}. + // Even if output shape is changed to {1,3,1,5}, there is another problem. It is that shape of + // output tensor used at next operation is changed to {1,3,1,5} after this operation even if the + // next operation is not desired. + if (ifm_shape.rank() == 4 && ifm_shape.rank() != ofm_shape.rank()) + { + if (ofm_shape.rank() == 2) + { + // Reducing HW + assert(ifm_shape.dim(0) == ofm_shape.dim(0) && ifm_shape.dim(3) == ofm_shape.dim(1)); + } + else if (ofm_shape.rank() == 3) + { + // Reducing C or + // (Reducing H and C(ifm and ofm) == 1) or (Reducing W and C(ifm and ofm) == 1) + assert(ifm_shape.dim(0) == ofm_shape.dim(0) && ifm_shape.dim(1) == ofm_shape.dim(1) && + ifm_shape.dim(2) == ofm_shape.dim(2) || + (ifm_shape.dim(0) == ofm_shape.dim(0) && + (ifm_shape.dim(1) == ofm_shape.dim(1) || ifm_shape.dim(2) == ofm_shape.dim(1)) && + ifm_shape.dim(3) == 1 && ofm_shape.dim(2) == 1)); + } + } + + _builder.addShapeConstr( + ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(), + _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint())); + _builder.addShapeConstr( + ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(), + _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint())); + + std::set<uint32_t> axis; + { + const auto ifm_rank = ifm_shape.rank(); + switch (axis_shape.rank()) + { + case 0: // scalar + { + int32_t axis_value = _ctx.at(axis_index).asScalar<int32_t>(); + if (axis_value < 0) + { + axis_value += ifm_rank; + } + axis.insert(ToARMComputeAxis(ifm_rank, axis_value).value()); + break; + } + case 1: // vector + { + const auto axis_base = _ctx.at(axis_index).data().base(); + const auto axis_size = _ctx.at(axis_index).shape().asVector(); + + // If axis's data does not exist as constant values and can be gotten as input data, we have + // to find a way to infer output shape when sinking output. + assert(axis_base != nullptr); + for (uint32_t n = 0; n < axis_size; ++n) + { + int32_t axis_value = *(reinterpret_cast<const int32_t *>(axis_base) + n); + if (axis_value < 0) + { + axis_value += ifm_rank; + } + axis.insert(ToARMComputeAxis(ifm_rank, axis_value).value()); + } + break; + } + default: + throw std::runtime_error("Not supported"); + break; + } + } + + // Construct operation parameters + struct Param + { + int ofm_index; + int ifm_index; + std::set<uint32_t> axis; + }; + + Param param; + + param.ofm_index = ofm_index.asInt(); + param.ifm_index = ifm_index.asInt(); + param.axis = axis; + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index}); + auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index}); + + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLReduceOperation>(); + + fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc), param.axis, + ::arm_compute::ReduceOperation::MAX); + + builder.append("ReduceMax", std::move(fn)); + } + else + throw std::runtime_error("Not supported, yet"); + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::Cast::Node &node) +{ + const ::internal::tflite::operand::Index output_index{node.param().output_index}; + const ::internal::tflite::operand::Index input_index{node.param().input_index}; + + assert(_ctx.at(output_index).shape() == _ctx.at(input_index).shape()); + + _builder.addShapeConstr(output_index, + asTensorInfo(asTensorShape(_ctx.at(output_index).shape()), + _ctx.at(output_index).type(), _ctx.at(output_index).scale(), + _ctx.at(output_index).zeroPoint())); + _builder.addShapeConstr(input_index, + asTensorInfo(asTensorShape(_ctx.at(input_index).shape()), + _ctx.at(input_index).type(), _ctx.at(input_index).scale(), + _ctx.at(input_index).zeroPoint())); + + // Construct operation parameters + struct Param + { + int input_index; + int output_index; + }; + + Param param; + + param.output_index = output_index.asInt(); + param.input_index = input_index.asInt(); + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.output_index}); + auto input_alloc = ctx.at(::internal::tflite::operand::Index{param.input_index}); + + std::unique_ptr<::arm_compute::IFunction> fn; + + { + if (::internal::arm_compute::isGpuMode()) + { + auto l = nnfw::cpp14::make_unique<::arm_compute::CLCast>(); + + l->configure(CAST_CL(input_alloc), CAST_CL(output_alloc)); + fn = std::move(l); + } + else + throw std::runtime_error("Not supported, yet"); + } + + builder.append("Cast", std::move(fn)); + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::TopKV2::Node &node) +{ + const ::internal::tflite::operand::Index outputValues_index{node.param().outputValues_index}; + const ::internal::tflite::operand::Index outputIndices_index{node.param().outputIndices_index}; + + const ::internal::tflite::operand::Index inputData_index{node.param().inputData_index}; + const ::internal::tflite::operand::Index k_index{node.param().k_index}; + + // Currently, we only support the vector input. + assert(_ctx.at(inputData_index).shape().rank() == 1 || + _ctx.at(inputData_index).shape().rank() == 2); + + const int32_t k = _ctx.at(k_index).asScalar<int32_t>(); + + // Set shape constraints + _builder.addShapeConstr(outputValues_index, + asTensorInfo(asTensorShape(_ctx.at(outputValues_index).shape()), + _ctx.at(outputValues_index).type(), + _ctx.at(outputValues_index).scale(), + _ctx.at(outputValues_index).zeroPoint())); + _builder.addShapeConstr(outputIndices_index, + asTensorInfo(asTensorShape(_ctx.at(outputIndices_index).shape()), + _ctx.at(outputIndices_index).type(), + _ctx.at(outputIndices_index).scale(), + _ctx.at(outputIndices_index).zeroPoint())); + _builder.addShapeConstr( + inputData_index, + asTensorInfo(asTensorShape(_ctx.at(inputData_index).shape()), _ctx.at(inputData_index).type(), + _ctx.at(inputData_index).scale(), _ctx.at(inputData_index).zeroPoint())); + + // Construct operation parameters + struct Param + { + int32_t outputValues_index; + int32_t outputIndices_index; + + int32_t inputData_index; + int32_t k; + }; + + Param param; + + param.outputValues_index = outputValues_index.asInt(); + param.outputIndices_index = outputIndices_index.asInt(); + param.inputData_index = inputData_index.asInt(); + param.k = k; + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto values_alloc = ctx.at(::internal::tflite::operand::Index{param.outputValues_index}); + auto indices_alloc = ctx.at(::internal::tflite::operand::Index{param.outputIndices_index}); + auto input_alloc = ctx.at(::internal::tflite::operand::Index{param.inputData_index}); + + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLTopKV2>(); + + fn->configure(CAST_CL(input_alloc), param.k, CAST_CL(values_alloc), CAST_CL(indices_alloc)); + + builder.append("TopKV2", std::move(fn)); + } + else + throw std::runtime_error("Not supported, yet"); + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::Gather::Node &node) +{ + const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index}; + + const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index}; + const ::internal::tflite::operand::Index indices_index{node.param().indices_index}; + + const ::internal::tflite::operand::Index axis_index{node.param().axis_index}; + + const auto ifm_shape = _ctx.at(ifm_index).shape(); + const auto indices_shape = _ctx.at(indices_index).shape(); + const auto axis_shape = _ctx.at(axis_index).shape(); + const auto ofm_shape = _ctx.at(ofm_index).shape(); + + assert(ifm_shape.rank() <= 4); + assert(indices_shape.rank() <= 3); + assert(ofm_shape.rank() <= 4); + assert(_ctx.at(axis_index).hasData()); + assert(axis_shape.rank() == 0); + + // Set Shape Constraints + _builder.addShapeConstr(ofm_index, + asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape(), false), + _ctx.at(ofm_index).type(), _ctx.at(ofm_index).scale(), + _ctx.at(ofm_index).zeroPoint())); + _builder.addShapeConstr(ifm_index, + asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape(), false), + _ctx.at(ifm_index).type(), _ctx.at(ifm_index).scale(), + _ctx.at(ifm_index).zeroPoint())); + _builder.addShapeConstr( + indices_index, asTensorInfo(asTensorShape(_ctx.at(indices_index).shape(), false), + _ctx.at(indices_index).type(), _ctx.at(indices_index).scale(), + _ctx.at(indices_index).zeroPoint())); + + const int32_t axis_value = static_cast<int>(_ctx.at(axis_index).asScalar<int32_t>()); + const int axis = ToARMComputeAxis(ifm_shape.rank(), axis_value).value(); + + // Construct operation parameters + struct Param + { + int ofm_index; + int ifm_index; + int indices_index; + + int axis; + }; + + Param param; + + param.ofm_index = ofm_index.asInt(); + param.ifm_index = ifm_index.asInt(); + param.indices_index = indices_index.asInt(); + + param.axis = axis; + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index}); + auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index}); + auto indices_alloc = ctx.at(::internal::tflite::operand::Index{param.indices_index}); + + if (::internal::arm_compute::isGpuMode()) + { + std::unique_ptr<::arm_compute::IFunction> fn; + + auto l = nnfw::cpp14::make_unique<GenericGather>(); + l->configure(CAST_CL(ifm_alloc), CAST_CL(indices_alloc), CAST_CL(ofm_alloc), param.axis); + fn = std::move(l); + builder.append("Gather", std::move(fn)); + } + else + throw std::runtime_error("Not supported, yet"); + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::PReLU::Node &node) +{ + VERBOSE(PReLU) << "Configure PReLU operation" << std::endl; + + const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index}; + const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index}; + const ::internal::tflite::operand::Index alpha_index{node.param().alpha_index}; + + // Set Shape Constraints and TensorInfo + _builder.addShapeConstr( + ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(), + _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint())); + + if (!(_ctx.at(ifm_index).shape() == _ctx.at(alpha_index).shape())) + { + const auto broadcast_rank = + std::max(_ctx.at(ifm_index).shape().rank(), _ctx.at(alpha_index).shape().rank()); + const_cast<::internal::tflite::operand::Shape &>(_ctx.at(ifm_index).shape()) + .extendRank(broadcast_rank); + const_cast<::internal::tflite::operand::Shape &>(_ctx.at(alpha_index).shape()) + .extendRank(broadcast_rank); + } + _builder.addShapeConstr( + ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(), + _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint())); + + _builder.addShapeConstr(alpha_index, + asTensorInfo(asTensorShape(_ctx.at(alpha_index).shape()), + _ctx.at(alpha_index).type(), _ctx.at(alpha_index).scale(), + _ctx.at(alpha_index).zeroPoint())); + + struct Param + { + int ofm_index; + int ifm_index; + int alpha_index; + }; + + Param param; + + param.ofm_index = ofm_index.asInt(); + param.ifm_index = ifm_index.asInt(); + param.alpha_index = alpha_index.asInt(); + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index}); + auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index}); + auto alpha_alloc = ctx.at(::internal::tflite::operand::Index{param.alpha_index}); + + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLPReLU>(); + fn->configure(CAST_CL(ifm_alloc), CAST_CL(alpha_alloc), CAST_CL(ofm_alloc)); + builder.append("PReLU", std::move(fn)); + } + else + { + // TODO Add NEON support + + throw std::runtime_error("Not supported, yet"); + } + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::ReLU::Node &node) +{ + VERBOSE(ReLU) << "Configure ReLU operation" << std::endl; + + const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index}; + const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index}; + + // Set shape constraints + _builder.addShapeConstr( + ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(), + _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint())); + _builder.addShapeConstr( + ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(), + _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint())); + + struct Param + { + int ofm_index; + int ifm_index; + }; + + Param param; + + param.ofm_index = ofm_index.asInt(); + param.ifm_index = ifm_index.asInt(); + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index}); + auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index}); + + const ::arm_compute::ActivationLayerInfo act_info{ + ::arm_compute::ActivationLayerInfo::ActivationFunction::RELU}; + + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLActivationLayer>(); + + fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc), act_info); + + builder.append("ReLU", std::move(fn)); + } + else + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::NEActivationLayer>(); + + fn->configure(ifm_alloc, ofm_alloc, act_info); + + builder.append("ReLU", std::move(fn)); + } + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::ReLU1::Node &node) +{ + VERBOSE(ReLU1) << "Configure ReLU1 operation" << std::endl; + + const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index}; + const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index}; + + // Set shape constraints + _builder.addShapeConstr( + ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(), + _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint())); + _builder.addShapeConstr( + ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(), + _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint())); + + struct Param + { + int ofm_index; + int ifm_index; + }; + + Param param; + + param.ofm_index = ofm_index.asInt(); + param.ifm_index = ifm_index.asInt(); + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index}); + auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index}); + + const ::arm_compute::ActivationLayerInfo act_info{ + ::arm_compute::ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, 1.0f, -1.0f}; + + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLActivationLayer>(); + + fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc), act_info); + + builder.append("ReLU1", std::move(fn)); + } + else + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::NEActivationLayer>(); + + fn->configure(ifm_alloc, ofm_alloc, act_info); + + builder.append("ReLU1", std::move(fn)); + } + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::ReLU6::Node &node) +{ + VERBOSE(ReLU6) << "Configure ReLU6 operation" << std::endl; + + const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index}; + const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index}; + + // Set shape constraints + _builder.addShapeConstr( + ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(), + _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint())); + _builder.addShapeConstr( + ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(), + _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint())); + + struct Param + { + int ofm_index; + int ifm_index; + }; + + Param param; + + param.ofm_index = ofm_index.asInt(); + param.ifm_index = ifm_index.asInt(); + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index}); + auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index}); + + const ::arm_compute::ActivationLayerInfo act_info{ + ::arm_compute::ActivationLayerInfo::ActivationFunction::BOUNDED_RELU, 6.0f}; + + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLActivationLayer>(); + + fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc), act_info); + + builder.append("ReLU6", std::move(fn)); + } + else + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::NEActivationLayer>(); + + fn->configure(ifm_alloc, ofm_alloc, act_info); + + builder.append("ReLU6", std::move(fn)); + } + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::Tanh::Node &node) +{ + VERBOSE(Tanh) << "Configure Tanh operation" << std::endl; + + const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index}; + const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index}; + + // Set shape constraints + _builder.addShapeConstr( + ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(), + _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint())); + _builder.addShapeConstr( + ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(), + _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint())); + + struct Param + { + int ofm_index; + int ifm_index; + }; + + Param param; + + param.ofm_index = ofm_index.asInt(); + param.ifm_index = ifm_index.asInt(); + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index}); + auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index}); + + const ::arm_compute::ActivationLayerInfo act_info{ + ::arm_compute::ActivationLayerInfo::ActivationFunction::TANH, 1.0f, 1.0f}; + + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLActivationLayer>(); + + fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc), act_info); + + builder.append("Tanh", std::move(fn)); + } + else + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::NEActivationLayer>(); + + fn->configure(ifm_alloc, ofm_alloc, act_info); + + builder.append("Tanh", std::move(fn)); + } + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::Logistic::Node &node) +{ + VERBOSE(Logistic) << "Configure Logistic operation" << std::endl; + + const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index}; + const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index}; + + // Set shape constraints + _builder.addShapeConstr( + ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(), + _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint())); + _builder.addShapeConstr( + ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(), + _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint())); + + struct Param + { + int ofm_index; + int ifm_index; + }; + + Param param; + + param.ofm_index = ofm_index.asInt(); + param.ifm_index = ifm_index.asInt(); + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index}); + auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index}); + + const ::arm_compute::ActivationLayerInfo act_info{ + ::arm_compute::ActivationLayerInfo::ActivationFunction::LOGISTIC}; + + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLActivationLayer>(); + + fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc), act_info); + + builder.append("Logistic", std::move(fn)); + } + else + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::NEActivationLayer>(); + + fn->configure(ifm_alloc, ofm_alloc, act_info); + + builder.append("Logistic", std::move(fn)); + } + }; + + _builder.addStage(stage); +} + +// Reduce Mean +void Planner::visit(const ::internal::tflite::op::Mean::Node &node) +{ + VERBOSE(Mean) << "Configure Mean operation" << std::endl; + + const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index}; + const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index}; + const ::internal::tflite::operand::Index axis_index{node.param().axis_index}; + const ::internal::tflite::operand::Index keep_dims_index{node.param().keep_dims_index}; + const int keep_dims = _ctx.at(keep_dims_index).asScalar<int>(); + + const auto ifm_shape = _ctx.at(ifm_index).shape(); + const auto ofm_shape = _ctx.at(ofm_index).shape(); + + // NOTE For the 4-dimensions, if the rank of input and output are different, this runtime only + // supports cases reducing height and width or reducing depth. + // TODO We have to support all cases of dimensions up to 4. + // For correct permuting, we have to set output's shape to be equal in dimension position of the + // input. But the positions of the same dimensions in the input and output may be set differently. + // For example {2,3,4,5}(input's shape) can be reduced to {3,5}(output's shape). The original + // output shape should be {1,3,1,5}, but real output shape may be {3,5}. If you simply try to + // extend it in 4 dimensions, it should be {1,1,3,5}. + // Even if output shape is changed to {1,3,1,5}, there is another problem. It is that shape of + // output tensor used at next operation is changed to {1,3,1,5} after this operation even if the + // next operation is not desired. + if (ifm_shape.rank() == 4 && ifm_shape.rank() != ofm_shape.rank()) + { + if (ofm_shape.rank() == 2) + { + // Reducing HW + assert(ifm_shape.dim(0) == ofm_shape.dim(0) && ifm_shape.dim(3) == ofm_shape.dim(1)); + } + else if (ofm_shape.rank() == 3) + { + // Reducing C or + // (Reducing H and C(ifm and ofm) == 1) or (Reducing W and C(ifm and ofm) == 1) + assert(ifm_shape.dim(0) == ofm_shape.dim(0) && ifm_shape.dim(1) == ofm_shape.dim(1) && + ifm_shape.dim(2) == ofm_shape.dim(2) || + (ifm_shape.dim(0) == ofm_shape.dim(0) && + (ifm_shape.dim(1) == ofm_shape.dim(1) || ifm_shape.dim(2) == ofm_shape.dim(1)) && + ifm_shape.dim(3) == 1 && ofm_shape.dim(2) == 1)); + } + } + + // Set shape constraints + _builder.addShapeConstr( + ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(), + _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint())); + _builder.addShapeConstr( + ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(), + _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint())); + _builder.addShapeConstr(axis_index, + asTensorInfo(asTensorShape(_ctx.at(axis_index).shape()), + _ctx.at(axis_index).type(), _ctx.at(axis_index).scale(), + _ctx.at(axis_index).zeroPoint())); + + std::set<uint32_t> axis; + { + const auto ifm_rank = ifm_shape.rank(); + const auto axis_shape = _ctx.at(axis_index).shape(); + switch (axis_shape.rank()) + { + case 0: // scalar + { + int32_t axis_value = _ctx.at(axis_index).asScalar<int32_t>(); + if (axis_value < 0) + { + axis_value += ifm_rank; + } + axis.insert(ToARMComputeAxis(ifm_rank, axis_value).value()); + break; + } + case 1: // vector + { + const auto axis_base = _ctx.at(axis_index).data().base(); + const auto axis_size = _ctx.at(axis_index).shape().asVector(); + + // If axis's data does not exist as constant values and can be gotten as input data, we have + // to find a way to infer output shape when sinking output. + assert(axis_base != nullptr); + for (uint32_t n = 0; n < axis_size; ++n) + { + int32_t axis_value = *(reinterpret_cast<const int32_t *>(axis_base) + n); + if (axis_value < 0) + { + axis_value += ifm_rank; + } + axis.insert(ToARMComputeAxis(ifm_rank, axis_value).value()); + } + break; + } + default: + throw std::runtime_error("Not supported"); + break; + } + } + + struct Param + { + int ofm_index; + int ifm_index; + bool keep_dims; + std::set<uint32_t> axis; + }; + + Param param; + + param.ofm_index = ofm_index.asInt(); + param.ifm_index = ifm_index.asInt(); + param.keep_dims = keep_dims > 0 ? true : false; + param.axis = axis; + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index}); + auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index}); + + ::arm_compute::Coordinates reduction_axis; + size_t i = 0; + for (auto index : param.axis) + { + reduction_axis.set(i++, index); + } + + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLReduceMean>(); + + fn->configure(CAST_CL(ifm_alloc), reduction_axis, param.keep_dims, CAST_CL(ofm_alloc)); + + builder.append("Mean", std::move(fn)); + } + else + throw std::runtime_error("Not supported, yet"); + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::RNN::Node &node) +{ + const ::internal::tflite::operand::Index output_index{node.param().output_index}; + const ::internal::tflite::operand::Index hidden_state_out_index{ + node.param().hidden_state_out_index}; + + const ::internal::tflite::operand::Index input_index{node.param().input_index}; + const ::internal::tflite::operand::Index weights_index{node.param().weights_index}; + const ::internal::tflite::operand::Index recurrent_weights_index{ + node.param().recurrent_weights_index}; + const ::internal::tflite::operand::Index bias_index{node.param().bias_index}; + const ::internal::tflite::operand::Index hidden_state_in_index{ + node.param().hidden_state_in_index}; + const ::internal::tflite::operand::Index fused_activation_index{ + node.param().fused_activation_index}; + + assert(_ctx.at(output_index).shape().rank() == 2 && + _ctx.at(hidden_state_out_index).shape().rank() == 2 && + _ctx.at(input_index).shape().rank() == 2 && _ctx.at(weights_index).shape().rank() == 2 && + _ctx.at(recurrent_weights_index).shape().rank() == 2 && + _ctx.at(hidden_state_in_index).shape().rank() == 2); + assert(_ctx.at(bias_index).shape().rank() == 1); + + const auto batch_size = _ctx.at(output_index).shape().dim(0); + assert(batch_size == _ctx.at(input_index).shape().dim(0) && + batch_size == _ctx.at(hidden_state_in_index).shape().dim(0) && + batch_size == _ctx.at(hidden_state_out_index).shape().dim(0)); + assert(_ctx.at(input_index).shape().dim(1) == _ctx.at(weights_index).shape().dim(1)); + + const auto num_units = _ctx.at(output_index).shape().dim(1); + assert(num_units == _ctx.at(weights_index).shape().dim(0) && + num_units == _ctx.at(recurrent_weights_index).shape().dim(0) && + num_units == _ctx.at(bias_index).shape().dim(0)); + assert(num_units == _ctx.at(output_index).shape().dim(1) && + num_units == _ctx.at(recurrent_weights_index).shape().dim(1) && + num_units == _ctx.at(hidden_state_in_index).shape().dim(1) && + num_units == _ctx.at(hidden_state_out_index).shape().dim(1)); + + // Set Shape Constraints and TensorInfo + _builder.addShapeConstr(output_index, + asTensorInfo(asTensorShape(_ctx.at(output_index).shape()), + _ctx.at(output_index).type(), _ctx.at(output_index).scale(), + _ctx.at(output_index).zeroPoint())); + _builder.addShapeConstr(hidden_state_out_index, + asTensorInfo(asTensorShape(_ctx.at(hidden_state_out_index).shape()), + _ctx.at(hidden_state_out_index).type(), + _ctx.at(hidden_state_out_index).scale(), + _ctx.at(hidden_state_out_index).zeroPoint())); + _builder.addShapeConstr(input_index, + asTensorInfo(asTensorShape(_ctx.at(input_index).shape()), + _ctx.at(input_index).type(), _ctx.at(input_index).scale(), + _ctx.at(input_index).zeroPoint())); + _builder.addShapeConstr(weights_index, asTensorInfo(asTensorShape(_ctx.at(weights_index).shape()), + _ctx.at(weights_index).type(), + _ctx.at(weights_index).scale(), + _ctx.at(weights_index).zeroPoint())); + _builder.addShapeConstr(recurrent_weights_index, + asTensorInfo(asTensorShape(_ctx.at(recurrent_weights_index).shape()), + _ctx.at(recurrent_weights_index).type(), + _ctx.at(recurrent_weights_index).scale(), + _ctx.at(recurrent_weights_index).zeroPoint())); + _builder.addShapeConstr(bias_index, + asTensorInfo(asTensorShape(_ctx.at(bias_index).shape()), + _ctx.at(bias_index).type(), _ctx.at(bias_index).scale(), + _ctx.at(bias_index).zeroPoint())); + _builder.addShapeConstr(hidden_state_in_index, + asTensorInfo(asTensorShape(_ctx.at(hidden_state_in_index).shape()), + _ctx.at(hidden_state_in_index).type(), + _ctx.at(hidden_state_in_index).scale(), + _ctx.at(hidden_state_in_index).zeroPoint())); + + // Construct operation parameters + struct Param + { + int output_index; + int hidden_state_out_index; + + int input_index; + int weights_index; + int recurrent_weights_index; + int bias_index; + int hidden_state_in_index; + + FuseCode activation; + }; + + Param param; + + param.output_index = output_index.asInt(); + param.hidden_state_out_index = hidden_state_out_index.asInt(); + + param.input_index = input_index.asInt(); + param.weights_index = weights_index.asInt(); + param.recurrent_weights_index = recurrent_weights_index.asInt(); + param.bias_index = bias_index.asInt(); + param.hidden_state_in_index = hidden_state_in_index.asInt(); + param.activation = static_cast<FuseCode>(_ctx.at(fused_activation_index).asScalar<int32_t>()); + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.output_index}); + auto hidden_state_out_alloc = + ctx.at(::internal::tflite::operand::Index{param.hidden_state_out_index}); + auto input_alloc = ctx.at(::internal::tflite::operand::Index{param.input_index}); + auto weights_alloc = ctx.at(::internal::tflite::operand::Index{param.weights_index}); + auto recurrent_weights_alloc = + ctx.at(::internal::tflite::operand::Index{param.recurrent_weights_index}); + auto bias_alloc = ctx.at(::internal::tflite::operand::Index{param.bias_index}); + auto hidden_state_in_alloc = + ctx.at(::internal::tflite::operand::Index{param.hidden_state_in_index}); + auto act_info = asActivationInfo(param.activation); + + if (::internal::arm_compute::isGpuMode()) + { + std::unique_ptr<::arm_compute::CLCopy> copy_fn{new ::arm_compute::CLCopy}; + copy_fn->configure(CAST_CL(hidden_state_in_alloc), CAST_CL(hidden_state_out_alloc)); + builder.append("COPY", std::move(copy_fn)); + + std::unique_ptr<::arm_compute::CLRNNLayer> rnn_fn{new ::arm_compute::CLRNNLayer}; + + // The hidden_state_in's data must be copied to hidden_state_out_alloc before fn->run() is + // performed. + rnn_fn->configure(CAST_CL(input_alloc), CAST_CL(weights_alloc), + CAST_CL(recurrent_weights_alloc), CAST_CL(bias_alloc), + CAST_CL(hidden_state_out_alloc), CAST_CL(output_alloc), act_info); + + builder.append("RNN", std::move(rnn_fn)); + } + else + throw std::runtime_error("Not supported, yet"); + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::LSTM::Node &node) +{ + // TODO Implement LSTM op + throw std::runtime_error("Not supported, yet"); +} + +void Planner::visit(const ::internal::tflite::op::Transpose::Node &node) +{ + VERBOSE(Transpose) << "Configure Transpose operation" << std::endl; + + const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index}; + const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index}; + const ::internal::tflite::operand::Index permu_index{node.param().permu_index}; + + assert(_ctx.at(ifm_index).shape().rank() == _ctx.at(ofm_index).shape().rank()); + assert(_ctx.at(permu_index).hasData() == true); + + // Set shape constraints + _builder.addShapeConstr( + ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(), + _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint())); + _builder.addShapeConstr( + ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(), + _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint())); + + struct Param + { + int ofm_index; + int ifm_index; + const int32_t *pv; + int rank; + }; + + Param param; + + param.ofm_index = ofm_index.asInt(); + param.ifm_index = ifm_index.asInt(); + param.pv = reinterpret_cast<const int32_t *>(_ctx.at(permu_index).data().base()); + param.rank = _ctx.at(ifm_index).shape().rank(); + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + + auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index}); + const auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index}); + + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLPermute>(); + + fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc), + getARMComputePermutationVector(param.rank, param.pv)); + + builder.append("Transpose", std::move(fn)); + } + else + { + throw std::runtime_error("Not supported, yet"); + } + + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::Floor::Node &node) +{ + VERBOSE(Floor) << "Configure Floor operation" << std::endl; + + const ::internal::tflite::operand::Index ofm_index{node.param().output_index}; + const ::internal::tflite::operand::Index ifm_index{node.param().input_index}; + + // Set shape constraints + _builder.addShapeConstr( + ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(), + _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint())); + _builder.addShapeConstr( + ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(), + _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint())); + + struct Param + { + int ofm_index; + int ifm_index; + }; + + Param param; + + param.ofm_index = ofm_index.asInt(); + param.ifm_index = ifm_index.asInt(); + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index}); + auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index}); + + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLFloor>(); + + fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc)); + + builder.append("Floor", std::move(fn)); + } + else + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::NEFloor>(); + + fn->configure(ifm_alloc, ofm_alloc); + + builder.append("Floor", std::move(fn)); + } + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::ArgMax::Node &node) +{ + VERBOSE(ArgMax) << "Configure ARGMAX operation" << std::endl; + + const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index}; + const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index}; + const ::internal::tflite::operand::Index axis_index{node.param().axis_index}; + + auto ifm_shape = _ctx.at(ifm_index).shape(); + auto ofm_shape = _ctx.at(ofm_index).shape(); + auto axis_shape = _ctx.at(axis_index).shape(); + + assert(_ctx.at(axis_index).hasData()); + // Axis dimension is always 1. + assert(axis_shape.rank() == 1); + assert((ifm_shape.rank() - 1) == ofm_shape.rank()); + + _builder.addShapeConstr(ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape(), false), + _ctx.at(ofm_index).type())); + _builder.addShapeConstr(ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape(), false), + _ctx.at(ifm_index).type())); + + std::vector<uint32_t> l_axis; + const auto axis_size = _ctx.at(axis_index).shape().asVector(); + auto axis_base = _ctx.at(axis_index).data().base(); + auto axis_type = _ctx.at(axis_index).type(); + // TODO Should support axis size > 1. + assert(axis_size == 1); + // axis is tensor with 1 dimension - always a vector. + assert(axis_base != nullptr); + for (uint32_t n = 0; n < axis_size; ++n) + { + int32_t axis_value = *(reinterpret_cast<const int32_t *>(axis_base) + n); + if (axis_value < 0) + { + axis_value += ifm_shape.rank(); + } + l_axis.push_back(ToARMComputeAxis(ifm_shape.rank(), axis_value).value()); + } + + // Construct operation parameters + struct Param + { + int ofm_index; + int ifm_index; + std::vector<uint32_t> axis; + }; + + Param param; + + param.ofm_index = ofm_index.asInt(); + param.ifm_index = ifm_index.asInt(); + param.axis = l_axis; + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index}); + auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index}); + + { + + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLArgOperation>(); + + fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc), param.axis, + ::arm_compute::ArgOperation::MAX); + + builder.append("ArgMax", std::move(fn)); + } + else + throw std::runtime_error("Not supported, yet"); + } + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::SQRT::Node &node) +{ + VERBOSE(SQRT) << "Configure SQRT operation" << std::endl; + + const ::internal::tflite::operand::Index output_index{node.param().output_index}; + const ::internal::tflite::operand::Index input_index{node.param().input_index}; + + // Set shape constraints + _builder.addShapeConstr(output_index, + asTensorInfo(asTensorShape(_ctx.at(output_index).shape()), + _ctx.at(output_index).type(), _ctx.at(output_index).scale(), + _ctx.at(output_index).zeroPoint())); + _builder.addShapeConstr(input_index, + asTensorInfo(asTensorShape(_ctx.at(input_index).shape()), + _ctx.at(input_index).type(), _ctx.at(input_index).scale(), + _ctx.at(input_index).zeroPoint())); + + struct Param + { + int output_index; + int input_index; + }; + + Param param; + + param.output_index = output_index.asInt(); + param.input_index = input_index.asInt(); + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.output_index}); + auto input_alloc = ctx.at(::internal::tflite::operand::Index{param.input_index}); + + const ::arm_compute::ActivationLayerInfo act_info{ + ::arm_compute::ActivationLayerInfo::ActivationFunction::SQRT}; + + { + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLActivationLayer>(); + + fn->configure(CAST_CL(input_alloc), CAST_CL(output_alloc), act_info); + + builder.append("SQRT", std::move(fn)); + } + else + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::NEActivationLayer>(); + + fn->configure(input_alloc, output_alloc, act_info); + + builder.append("SQRT", std::move(fn)); + } + } + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::RSQRT::Node &node) +{ + VERBOSE(RSQRT) << "Configure Rsqrt operation" << std::endl; + + const ::internal::tflite::operand::Index output_index{node.param().output_index}; + const ::internal::tflite::operand::Index input_index{node.param().input_index}; + + // Set shape constraints + _builder.addShapeConstr(output_index, + asTensorInfo(asTensorShape(_ctx.at(output_index).shape()), + _ctx.at(output_index).type(), _ctx.at(output_index).scale(), + _ctx.at(output_index).zeroPoint())); + _builder.addShapeConstr(input_index, + asTensorInfo(asTensorShape(_ctx.at(input_index).shape()), + _ctx.at(input_index).type(), _ctx.at(input_index).scale(), + _ctx.at(input_index).zeroPoint())); + + struct Param + { + int output_index; + int input_index; + }; + + Param param; + + param.output_index = output_index.asInt(); + param.input_index = input_index.asInt(); + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.output_index}); + auto input_alloc = ctx.at(::internal::tflite::operand::Index{param.input_index}); + + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLRsqrtLayer>(); + + fn->configure(CAST_CL(input_alloc), CAST_CL(output_alloc)); + + builder.append("RSQRT", std::move(fn)); + } + else + throw std::runtime_error("Not supported, yet"); + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::Equal::Node &node) +{ + const ::internal::tflite::operand::Index output_index{node.param().output_index}; + const ::internal::tflite::operand::Index input1_index{node.param().input1_index}; + const ::internal::tflite::operand::Index input2_index{node.param().input2_index}; + + // Set Shape Constraints and TensorInfo + _builder.addShapeConstr(output_index, + asTensorInfo(asTensorShape(_ctx.at(output_index).shape()), + _ctx.at(output_index).type(), _ctx.at(output_index).scale(), + _ctx.at(output_index).zeroPoint())); + + if (!(_ctx.at(input1_index).shape() == _ctx.at(input2_index).shape())) + { + const auto broadcast_rank = + std::max(_ctx.at(input1_index).shape().rank(), _ctx.at(input2_index).shape().rank()); + const_cast<::internal::tflite::operand::Shape &>(_ctx.at(input1_index).shape()) + .extendRank(broadcast_rank); + const_cast<::internal::tflite::operand::Shape &>(_ctx.at(input2_index).shape()) + .extendRank(broadcast_rank); + } + _builder.addShapeConstr(input1_index, + asTensorInfo(asTensorShape(_ctx.at(input1_index).shape()), + _ctx.at(input1_index).type(), _ctx.at(input1_index).scale(), + _ctx.at(input1_index).zeroPoint())); + _builder.addShapeConstr(input2_index, + asTensorInfo(asTensorShape(_ctx.at(input2_index).shape()), + _ctx.at(input2_index).type(), _ctx.at(input2_index).scale(), + _ctx.at(input2_index).zeroPoint())); + + // Construct operation parameters + struct Param + { + int output_index; + int input1_index; + int input2_index; + }; + + Param param; + + param.output_index = output_index.asInt(); + param.input1_index = input1_index.asInt(); + param.input2_index = input2_index.asInt(); + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.output_index}); + auto input1_alloc = ctx.at(::internal::tflite::operand::Index{param.input1_index}); + auto input2_alloc = ctx.at(::internal::tflite::operand::Index{param.input2_index}); + + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLComparison>(); + + fn->configure(CAST_CL(input1_alloc), CAST_CL(input2_alloc), CAST_CL(output_alloc), + ::arm_compute::ComparisonOperation::Equal); + + builder.append("Equal", std::move(fn)); + } + else + { + // TODO Add NEON support + + throw std::runtime_error("Not supported, yet"); + } + }; + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::TransposeConv::Node &node) +{ + VERBOSE(TransposeConv) << "Configure TransposeConv operation" << std::endl; + + const ::internal::tflite::operand::Index op_shape_index{node.param().op_shape_index}; + const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index}; + const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index}; + const ::internal::tflite::operand::Index ker_index{node.param().ker_index}; + + const ::internal::tflite::operand::Index padding_index{node.param().padding_index}; + const ::internal::tflite::operand::Index hstride_index{node.param().hstride_index}; + const ::internal::tflite::operand::Index vstride_index{node.param().vstride_index}; + + // Only 4D tensors are supported + assert(_ctx.at(ofm_index).shape().rank() == 4); + assert(_ctx.at(ofm_index).shape().rank() == _ctx.at(ifm_index).shape().rank()); + assert(_ctx.at(ofm_index).shape().rank() == _ctx.at(ker_index).shape().rank()); + + const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(); + const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(); + const auto ker_shape = _ctx.at(ker_index).shape().asFeature(); + + assert(_ctx.at(padding_index).hasData() == true); + + const int32_t vstride = _ctx.at(vstride_index).asScalar<int32_t>(); + const int32_t hstride = _ctx.at(hstride_index).asScalar<int32_t>(); + + const PaddingCode padding_type = + static_cast<PaddingCode>(_ctx.at(padding_index).asScalar<int32_t>()); + + assert(vstride > 0); + assert(hstride > 0); + assert((ANEURALNETWORKS_PADDING_SAME == padding_type) || + (ANEURALNETWORKS_PADDING_VALID == padding_type)); + assert(ifm_shape.N == ofm_shape.N); + assert(ifm_shape.C == ker_shape.C); + assert(ker_shape.N == ofm_shape.C); + + // Set Shape Constraints and TensorInfo + _builder.addShapeConstr( + ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(), + _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint())); + _builder.addShapeConstr( + ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(), + _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint())); + _builder.addShapeConstr( + ker_index, asTensorInfo(asTensorShape(_ctx.at(ker_index).shape()), _ctx.at(ker_index).type(), + _ctx.at(ker_index).scale(), _ctx.at(ker_index).zeroPoint())); + + // Construct operation parameters + struct Param + { + int ofm_index; + int ifm_index; + int ker_index; + Padding padding; + Stride stride; + uint32_t invalid_horizontal; + uint32_t invalid_vertical; + }; + + Param param; + + param.ofm_index = ofm_index.asInt(); + param.ifm_index = ifm_index.asInt(); + param.ker_index = ker_index.asInt(); + + param.stride.horizontal = hstride; + param.stride.vertical = vstride; + + param.padding = (padding_type == ANEURALNETWORKS_PADDING_SAME) + ? same_padding(ofm_shape, ifm_shape, param.stride, ker_shape.W, ker_shape.H) + : valid_padding(); + + param.invalid_horizontal = + (padding_type == ANEURALNETWORKS_PADDING_SAME) + ? 0 + : ofm_shape.W - (1 + (ifm_shape.W - 1) * hstride) - (ker_shape.W - 1); + param.invalid_vertical = + (padding_type == ANEURALNETWORKS_PADDING_SAME) + ? 0 + : ofm_shape.H - (1 + (ifm_shape.H - 1) * param.stride.vertical) - (ker_shape.H - 1); + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index}); + auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index}); + auto ker_alloc = ctx.at(::internal::tflite::operand::Index{param.ker_index}); + + // Only rank 4 is supported + const int rank = 4; + + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLTransposeConvLayer>(); + + auto symmetric_tconv_info = asPadStrideInfo(param.padding, param.stride); + + // TODO Support WeightInfo in some cases in order to performance improvement + fn->configure(CAST_CL(ifm_alloc), CAST_CL(ker_alloc), nullptr, CAST_CL(ofm_alloc), + symmetric_tconv_info, param.invalid_horizontal, param.invalid_vertical); + builder.append("TransposeConv", std::move(fn)); + } + else + { + throw std::runtime_error("Not supported, yet"); + } + }; + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::SquaredDifference::Node &node) +{ + const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index}; + const ::internal::tflite::operand::Index lhs_index{node.param().lhs_index}; + const ::internal::tflite::operand::Index rhs_index{node.param().rhs_index}; + + // Set Shape Constraints and TensorInfo + _builder.addShapeConstr( + ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(), + _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint())); + + if (!(_ctx.at(lhs_index).shape() == _ctx.at(rhs_index).shape())) + { + const auto broadcast_rank = + std::max(_ctx.at(lhs_index).shape().rank(), _ctx.at(rhs_index).shape().rank()); + const_cast<::internal::tflite::operand::Shape &>(_ctx.at(lhs_index).shape()) + .extendRank(broadcast_rank); + const_cast<::internal::tflite::operand::Shape &>(_ctx.at(rhs_index).shape()) + .extendRank(broadcast_rank); + } + _builder.addShapeConstr( + lhs_index, asTensorInfo(asTensorShape(_ctx.at(lhs_index).shape()), _ctx.at(lhs_index).type(), + _ctx.at(lhs_index).scale(), _ctx.at(lhs_index).zeroPoint())); + _builder.addShapeConstr( + rhs_index, asTensorInfo(asTensorShape(_ctx.at(rhs_index).shape()), _ctx.at(rhs_index).type(), + _ctx.at(rhs_index).scale(), _ctx.at(rhs_index).zeroPoint())); + + // Construct operation parameters + struct Param + { + int ofm_index; + int lhs_index; + int rhs_index; + }; + + Param param; + + param.ofm_index = ofm_index.asInt(); + param.lhs_index = lhs_index.asInt(); + param.rhs_index = rhs_index.asInt(); + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index}); + auto lhs_alloc = ctx.at(::internal::tflite::operand::Index{param.lhs_index}); + auto rhs_alloc = ctx.at(::internal::tflite::operand::Index{param.rhs_index}); + + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLElementwiseSquaredDiff>(); + + fn->configure(CAST_CL(lhs_alloc), CAST_CL(rhs_alloc), CAST_CL(ofm_alloc)); + builder.append("SquaredDifference", std::move(fn)); + } + else + { + // TODO Enable NEON Support + throw std::runtime_error("Not supported, yet"); + } + + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::Split::Node &node) +{ + VERBOSE(Split) << "Configure Split operation" << std::endl; + + const ::internal::tflite::operand::Index axis_index{node.param().axis_index}; + const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index}; + + const auto ifm_shape = _ctx.at(ifm_index).shape(); + int32_t axis = _ctx.at(axis_index).asScalar<int32_t>(); + + // Handle negative axis + if (axis < 0) + { + axis += ifm_shape.rank(); + } + + const int32_t num_split = node.param().ofm_indexes.size(); + const auto input_size = ifm_shape.dim(axis); + assert(input_size % num_split == 0); + const int32_t slice_size = input_size / num_split; + + // Set Shape Constraints and TensorInfo (for input) + _builder.addShapeConstr(ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), + _ctx.at(ifm_index).type())); + + // Set Shape Constraints and TensorInfo (for output) + const auto rank = ifm_shape.rank(); + const uint32_t coord_index = ToARMComputeAxis(rank, axis).value(); + uint32_t depth = 0; + + ::arm_compute::Coordinates coordinates; + coordinates.set_num_dimensions(rank); + + for (const auto &index : node.param().ofm_indexes) + { + const ::internal::tflite::operand::Index ofm_index{index}; + + coordinates[coord_index] = depth; + + _builder.addSubsumptionConstr(ofm_index, ifm_index, coordinates, + asTensorShape(_ctx.at(ofm_index).shape()), true); + depth += slice_size; + } + + // NOTE Split has no actual operation! +} + +void Planner::visit(const ::internal::tflite::op::Pad::Node &node) +{ + const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index}; + const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index}; + const ::internal::tflite::operand::Index paddings_index{node.param().paddings_index}; + + assert(_ctx.at(paddings_index).hasData() == true); + + // Set Shape Constraints and TensorInfo + _builder.addShapeConstr(ifm_index, + asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape(), false), + _ctx.at(ifm_index).type(), _ctx.at(ifm_index).scale(), + _ctx.at(ifm_index).zeroPoint())); + _builder.addShapeConstr(ofm_index, + asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape(), false), + _ctx.at(ofm_index).type(), _ctx.at(ofm_index).scale(), + _ctx.at(ofm_index).zeroPoint())); + _builder.addShapeConstr( + paddings_index, asTensorInfo(asTensorShape(_ctx.at(paddings_index).shape(), false), + _ctx.at(paddings_index).type(), _ctx.at(paddings_index).scale(), + _ctx.at(paddings_index).zeroPoint())); + + // Construct operation parameters + struct Param + { + int ofm_index; + int ifm_index; + ::arm_compute::PixelValue pixel_value; + ::arm_compute::PaddingList padding_list; + }; + + Param param; + + param.ofm_index = ofm_index.asInt(); + param.ifm_index = ifm_index.asInt(); + + // initializer for padding + auto rank = _ctx.at(ifm_index).shape().rank(); + auto pad_type = _ctx.at(paddings_index).type(); + + if (pad_type == ANEURALNETWORKS_TENSOR_INT32) + { + auto pad_base = _ctx.at(paddings_index).data().base(); + auto pad_shape = _ctx.at(paddings_index).shape(); + + param.padding_list.resize(rank); + for (int32_t n = 0; n < rank; ++n) + { + const int32_t *from = reinterpret_cast<const int32_t *>(pad_base) + (n * pad_shape.dim(1)); + auto axis = ToARMComputeAxis(rank, n).value(); + + param.padding_list[axis] = ::arm_compute::PaddingInfo{from[0], from[1]}; + } + auto data_type = asDataType(_ctx.at(ifm_index).type()); + auto quant_info = + asQuantizationInfo(_ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint()); + param.pixel_value = ::arm_compute::PixelValue{0, data_type, quant_info}; + } + else + { + throw std::runtime_error("Only Int32 datatype is supported for Pad values"); + } + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index}); + auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index}); + + { + if (::internal::arm_compute::isGpuMode()) // GPU + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLPadLayer>(); + + fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc), param.padding_list, + param.pixel_value); + + builder.append("PAD", std::move(fn)); + } + else // NEON + { + // TODO Enable NEON Support + throw std::runtime_error("Not supported, yet"); + } + } + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::SpaceToDepth::Node &node) +{ + const ::internal::tflite::operand::Index output_index{node.param().output_index}; + const ::internal::tflite::operand::Index input_index{node.param().input_index}; + const ::internal::tflite::operand::Index block_size_index{node.param().block_size_index}; + + const auto input_batch = _ctx.at(input_index).shape().dim(0); + const auto output_batch = _ctx.at(output_index).shape().dim(0); + const auto input_depth = _ctx.at(input_index).shape().dim(3); + const auto output_depth = _ctx.at(output_index).shape().dim(3); + const auto block_size = _ctx.at(block_size_index).asScalar<int32_t>(); + const auto input_height = _ctx.at(input_index).shape().dim(1); + const auto input_width = _ctx.at(input_index).shape().dim(2); + + // All assertions as per NNAPI specification. + assert(_ctx.at(input_index).shape().rank() == 4); + assert(_ctx.at(output_index).shape().rank() == 4); + assert((block_size >= 1) && (input_height % block_size == 0) && (input_width % block_size == 0)); + assert(input_batch == output_batch); + assert(input_depth * block_size * block_size == output_depth); + + // Set Shape Constraints and TensorInfo + _builder.addShapeConstr(output_index, + asTensorInfo(asTensorShape(_ctx.at(output_index).shape(), false), + _ctx.at(output_index).type(), _ctx.at(output_index).scale(), + _ctx.at(output_index).zeroPoint())); + _builder.addShapeConstr(input_index, + asTensorInfo(asTensorShape(_ctx.at(input_index).shape(), false), + _ctx.at(input_index).type(), _ctx.at(input_index).scale(), + _ctx.at(input_index).zeroPoint())); + + // Construct operation parameters + struct Param + { + int output_index; + int input_index; + int32_t block_size; + }; + + Param param; + + param.output_index = output_index.asInt(); + param.input_index = input_index.asInt(); + param.block_size = block_size; + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.output_index}); + auto input_alloc = ctx.at(::internal::tflite::operand::Index{param.input_index}); + + { + if (::internal::arm_compute::isGpuMode()) // GPU + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLSpaceToDepth>(); + + fn->configure(CAST_CL(input_alloc), CAST_CL(output_alloc), param.block_size); + + builder.append("SpaceToDepth", std::move(fn)); + } + else // NEON + { + // TODO Enable NEON Support + throw std::runtime_error("Not supported, yet"); + } + } + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::SpaceToBatchND::Node &node) +{ + const ::internal::tflite::operand::Index output_index{node.param().output_index}; + const ::internal::tflite::operand::Index input_index{node.param().input_index}; + const ::internal::tflite::operand::Index block_size_index{node.param().block_size_index}; + const ::internal::tflite::operand::Index padding_size_index{node.param().padding_size_index}; + + const auto &output_shape = _ctx.at(output_index).shape(); + const auto &input_shape = _ctx.at(input_index).shape(); + const auto &padding_size_shape = _ctx.at(padding_size_index).shape(); + auto block_size_base = reinterpret_cast<const int32_t *>(_ctx.at(block_size_index).data().base()); + auto padding_size_base = + reinterpret_cast<const int32_t *>(_ctx.at(padding_size_index).data().base()); + + { // New block for assertions + const auto &block_size_shape = _ctx.at(block_size_index).shape(); + + // Currently, only 4D NHWC input/output op_context are supported. + // The 4D array need to have exactly 2 spatial dimensions. + // TODO: Support arbitrary dimension in SpaceToBatchND. + assert(input_shape.rank() == 4); + assert(output_shape.rank() == 4); + assert(block_size_shape.rank() == 1); + assert(padding_size_shape.rank() == 2); + + assert(output_shape.dim(3) == input_shape.dim(3)); + assert(block_size_shape.dim(0) == 2); + assert(padding_size_shape.dim(0) == 2); + assert(padding_size_shape.dim(1) == 2); + + assert(_ctx.at(block_size_index).hasData() && _ctx.at(padding_size_index).hasData()); + assert(_ctx.at(block_size_index).type() == ANEURALNETWORKS_TENSOR_INT32); + assert(_ctx.at(padding_size_index).type() == ANEURALNETWORKS_TENSOR_INT32); + + assert(block_size_base[0] > 0 && block_size_base[1] > 0); + assert(output_shape.dim(0) == input_shape.dim(0) * block_size_base[0] * block_size_base[1]); + assert(output_shape.dim(1) == + (input_shape.dim(1) + padding_size_base[0] + padding_size_base[1]) / block_size_base[0]); + assert(output_shape.dim(2) == + (input_shape.dim(2) + padding_size_base[2] + padding_size_base[3]) / block_size_base[1]); + } + + // Set Shape Constraints and TensorInfo + _builder.addShapeConstr(output_index, + asTensorInfo(asTensorShape(_ctx.at(output_index).shape(), false), + _ctx.at(output_index).type(), _ctx.at(output_index).scale(), + _ctx.at(output_index).zeroPoint())); + _builder.addShapeConstr(input_index, + asTensorInfo(asTensorShape(_ctx.at(input_index).shape(), false), + _ctx.at(input_index).type(), _ctx.at(input_index).scale(), + _ctx.at(input_index).zeroPoint())); + + _builder.addShapeConstr(block_size_index, + asTensorInfo(asTensorShape(_ctx.at(block_size_index).shape()), + _ctx.at(block_size_index).type(), + _ctx.at(block_size_index).scale(), + _ctx.at(block_size_index).zeroPoint())); + + _builder.addShapeConstr(padding_size_index, + asTensorInfo(asTensorShape(_ctx.at(padding_size_index).shape()), + _ctx.at(padding_size_index).type(), + _ctx.at(padding_size_index).scale(), + _ctx.at(padding_size_index).zeroPoint())); + + { // Append block_size initializer + auto initializer = [block_size_base](::arm_compute::ITensor &tensor) { + const auto block_size_y = block_size_base[0]; + const auto block_size_x = block_size_base[1]; + + auto into = reinterpret_cast<int32_t *>(tensor.ptr_to_element({0})); + into[0] = block_size_x; + into[1] = block_size_y; + }; + _builder.addInitializer(block_size_index, initializer); + } + + { // Append padding_size initializer + auto initializer = [padding_size_base, padding_size_shape](::arm_compute::ITensor &tensor) { + // If n == 0, then the axis is the height + // If n == 1, then the axis is the width + for (size_t n = 0; n < padding_size_shape.dim(0); ++n) + { + const auto from = padding_size_base + (n * padding_size_shape.dim(1)); + auto into = reinterpret_cast<int32_t *>(tensor.ptr_to_element({0, 1 - n})); + into[0] = from[0]; + into[1] = from[1]; + } + }; + _builder.addInitializer(padding_size_index, initializer); + } + + // Construct operation parameters + struct Param + { + int output_index; + int input_index; + int block_size_index; + int padding_size_index; + int32_t rank; + }; + + Param param; + + param.output_index = output_index.asInt(); + param.input_index = input_index.asInt(); + param.block_size_index = block_size_index.asInt(); + param.padding_size_index = padding_size_index.asInt(); + param.rank = _ctx.at(input_index).shape().rank(); + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.output_index}); + auto input_alloc = ctx.at(::internal::tflite::operand::Index{param.input_index}); + auto block_size_alloc = ctx.at(::internal::tflite::operand::Index{param.block_size_index}); + auto padding_size_alloc = ctx.at(::internal::tflite::operand::Index{param.padding_size_index}); + + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLSpaceToBatchND>(); + + fn->configure(CAST_CL(input_alloc), CAST_CL(block_size_alloc), CAST_CL(padding_size_alloc), + CAST_CL(output_alloc)); + builder.append("SpaceToBatchND", std::move(fn)); + } + else + { + // TODO Enable NEON Support + throw std::runtime_error("Not supported, yet"); + } + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::BatchToSpaceNd::Node &node) +{ + const ::internal::tflite::operand::Index output_index{node.param().output_index}; + const ::internal::tflite::operand::Index input_index{node.param().input_index}; + const ::internal::tflite::operand::Index block_size_index{node.param().block_size_index}; + + assert(_ctx.at(input_index).shape().rank() == 4); + assert(_ctx.at(output_index).shape().rank() == 4); + assert(_ctx.at(block_size_index).shape().rank() == 1); + assert(_ctx.at(block_size_index).hasData() == true); + + const int32_t *block_size = + reinterpret_cast<const int32_t *>(_ctx.at(block_size_index).data().base()); + + const auto &output_shape = _ctx.at(output_index).shape(); + const auto &input_shape = _ctx.at(input_index).shape(); + const auto &block_size_shape = _ctx.at(block_size_index).shape(); + + // Set Shape Constraints and TensorInfo + _builder.addShapeConstr( + output_index, asTensorInfo(asTensorShape(output_shape, false), _ctx.at(output_index).type(), + _ctx.at(output_index).scale(), _ctx.at(output_index).zeroPoint())); + _builder.addShapeConstr( + input_index, asTensorInfo(asTensorShape(input_shape, false), _ctx.at(input_index).type(), + _ctx.at(input_index).scale(), _ctx.at(input_index).zeroPoint())); + + _builder.addShapeConstr(block_size_index, asTensorInfo(asTensorShape(block_size_shape), + _ctx.at(block_size_index).type(), + _ctx.at(block_size_index).scale(), + _ctx.at(block_size_index).zeroPoint())); + + // initializer for block_size + { + const auto block_size_base = + reinterpret_cast<const int32_t *>(_ctx.at(block_size_index).data().base()); + + assert(output_shape.dim(3) == input_shape.dim(3)); + assert(output_shape.dim(1) == input_shape.dim(1) * block_size_base[0]); + assert(output_shape.dim(2) == input_shape.dim(2) * block_size_base[1]); + assert(output_shape.dim(0) == input_shape.dim(0) / (block_size_base[0] * block_size_base[1])); + assert(_ctx.at(block_size_index).type() == ANEURALNETWORKS_TENSOR_INT32); + + assert((_ctx.at(block_size_index).data().size() / sizeof(int32_t)) == 2 && + block_size_base[0] > 0 && block_size_base[1] > 0); + + auto initializer = [block_size_base](::arm_compute::ITensor &tensor) { + const int32_t *from = reinterpret_cast<const int32_t *>(block_size_base); + int32_t *into = reinterpret_cast<int32_t *>(tensor.ptr_to_element({0})); + into[0] = from[1]; + into[1] = from[0]; + }; + _builder.addInitializer(block_size_index, initializer); + } + + // Construct operation parameters + struct Param + { + int output_index; + int input_index; + int block_size_index; + const int32_t *block_size; + int32_t rank; + }; + + Param param; + + param.output_index = output_index.asInt(); + param.input_index = input_index.asInt(); + param.block_size_index = block_size_index.asInt(); + param.block_size = block_size; + param.rank = _ctx.at(input_index).shape().rank(); + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.output_index}); + auto input_alloc = ctx.at(::internal::tflite::operand::Index{param.input_index}); + auto block_size_alloc = ctx.at(::internal::tflite::operand::Index{param.block_size_index}); + + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLBatchToSpaceLayer>(); + + fn->configure(CAST_CL(input_alloc), CAST_CL(block_size_alloc), CAST_CL(output_alloc)); + builder.append("BatchToSpaceND", std::move(fn)); + } + else + { + // TODO Enable NEON Support + throw std::runtime_error("Not supported, yet"); + } + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::L2Normalization::Node &node) +{ + const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index}; + const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index}; + + // Set Shape Constraints and TensorInfo + _builder.addShapeConstr( + ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(), + _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint())); + + _builder.addShapeConstr( + ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(), + _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint())); + + // {CL|Neon}L2Normalization performs the reduction only along dimension 0 + // L2 Normalization always performs the reduction along the depth axis + // Thus, we repurpose {CL|Neon}NormalizationLayers to act as depthwise L2 normalizations by + // choosing normalization parameters as below + + // Construct operation parameters + struct Param + { + int ofm_index; + int ifm_index; + int32_t radius; + float alpha; + float beta; + float bias; + }; + + Param param; + + param.ofm_index = ofm_index.asInt(); + param.ifm_index = ifm_index.asInt(); + + param.radius = 2 * _ctx.at(ifm_index).shape().dim(3) + 1; // normSize = depth * 2 + 1 + param.alpha = 1.0f; // In the implementation to make alpha_ become 1 + param.beta = 0.5f; // pow(reduction, -0.5) = 1 / sqrt(reduction) + param.bias = 0.0f; // Don't offset the reduction. + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index}); + auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index}); + + const auto norm_info = + ::arm_compute::NormalizationLayerInfo(::arm_compute::NormType::CROSS_MAP, param.radius, + param.alpha, param.beta, param.bias, false); + + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLNormalizationLayer>(); + + fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc), norm_info); + + builder.append("L2Normalize", std::move(fn)); + } + else + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::NENormalizationLayer>(); + + fn->configure(ifm_alloc, ofm_alloc, norm_info); + + builder.append("L2Normalize", std::move(fn)); + } + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::L2Pool2D::Implicit::Node &node) + +{ + const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index}; + const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index}; + + const ::internal::tflite::operand::Index kh_index{node.param().kh_index}; + const ::internal::tflite::operand::Index kw_index{node.param().kw_index}; + + const ::internal::tflite::operand::Index vstride_index{node.param().vstride_index}; + const ::internal::tflite::operand::Index hstride_index{node.param().hstride_index}; + + const ::internal::tflite::operand::Index padding_index{node.param().padding_index}; + const ::internal::tflite::operand::Index activation_index{node.param().activation_index}; + + const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(); + const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(); + + const int32_t kh = _ctx.at(kh_index).asScalar<int32_t>(); + const int32_t kw = _ctx.at(kw_index).asScalar<int32_t>(); + + const int32_t vstride = _ctx.at(vstride_index).asScalar<int32_t>(); + const int32_t hstride = _ctx.at(hstride_index).asScalar<int32_t>(); + + const PaddingCode padding_type = + static_cast<PaddingCode>(_ctx.at(padding_index).asScalar<int32_t>()); + + assert((ANEURALNETWORKS_PADDING_SAME == padding_type) || + (ANEURALNETWORKS_PADDING_VALID == padding_type)); + + _builder.addShapeConstr( + ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(), + _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint())); + _builder.addShapeConstr( + ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(), + _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint())); + + struct Param + { + int ofm_index; + int ifm_index; + + uint32_t kw; + uint32_t kh; + + Padding padding; + Stride stride; + + FuseCode activation; + }; + + Param param; + + param.ofm_index = ofm_index.asInt(); + param.ifm_index = ifm_index.asInt(); + + param.kh = kh; + param.kw = kw; + + param.stride.vertical = vstride; + param.stride.horizontal = hstride; + + param.padding = (padding_type == ANEURALNETWORKS_PADDING_SAME) + ? same_padding(ifm_shape, ofm_shape, param.stride, kw, kh) + : valid_padding(); + param.activation = static_cast<FuseCode>(_ctx.at(activation_index).asScalar<int32_t>()); + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index}); + auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index}); + + ::arm_compute::PoolingLayerInfo info{::arm_compute::PoolingType::L2, + ::arm_compute::Size2D{param.kw, param.kh}, + asPadStrideInfo(param.padding, param.stride)}; + + if (::internal::arm_compute::isGpuMode()) + { + std::unique_ptr<::arm_compute::CLPoolingLayer> fn{new ::arm_compute::CLPoolingLayer}; + + fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc), info); + + builder.append("L2Pool2D", std::move(fn)); + } + else + { + std::unique_ptr<::arm_compute::NEPoolingLayer> fn{new ::arm_compute::NEPoolingLayer}; + + fn->configure(ifm_alloc, ofm_alloc, info); + + builder.append("L2Pool2D", std::move(fn)); + } + + ActivationBuilder{builder}.append(param.activation, ofm_alloc); + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::L2Pool2D::Explicit::Node &node) +{ + const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index}; + const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index}; + + const ::internal::tflite::operand::Index kh_index{node.param().kh_index}; + const ::internal::tflite::operand::Index kw_index{node.param().kw_index}; + + const ::internal::tflite::operand::Index vstride_index{node.param().vstride_index}; + const ::internal::tflite::operand::Index hstride_index{node.param().hstride_index}; + + const ::internal::tflite::operand::Index padding_left_index{node.param().padding_left_index}; + const ::internal::tflite::operand::Index padding_right_index{node.param().padding_right_index}; + const ::internal::tflite::operand::Index padding_top_index{node.param().padding_top_index}; + const ::internal::tflite::operand::Index padding_bottom_index{node.param().padding_bottom_index}; + + const ::internal::tflite::operand::Index activation_index{node.param().activation_index}; + + const int32_t kh = _ctx.at(kh_index).asScalar<int32_t>(); + const int32_t kw = _ctx.at(kw_index).asScalar<int32_t>(); + + const int32_t vstride = _ctx.at(vstride_index).asScalar<int32_t>(); + const int32_t hstride = _ctx.at(hstride_index).asScalar<int32_t>(); + + const int32_t padding_left = _ctx.at(padding_left_index).asScalar<int32_t>(); + const int32_t padding_right = _ctx.at(padding_right_index).asScalar<int32_t>(); + const int32_t padding_top = _ctx.at(padding_top_index).asScalar<int32_t>(); + const int32_t padding_bottom = _ctx.at(padding_bottom_index).asScalar<int32_t>(); + + _builder.addShapeConstr( + ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(), + _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint())); + _builder.addShapeConstr( + ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(), + _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint())); + + // Construct operation parameters + struct Param + { + int ofm_index; + int ifm_index; + + uint32_t kw; + uint32_t kh; + + Padding padding; + Stride stride; + + FuseCode activation; + }; + + Param param; + + param.ofm_index = ofm_index.asInt(); + param.ifm_index = ifm_index.asInt(); + + param.kh = kh; + param.kw = kw; + + param.stride.vertical = vstride; + param.stride.horizontal = hstride; + + param.padding.left = padding_left; + param.padding.right = padding_right; + param.padding.top = padding_top; + param.padding.bottom = padding_bottom; + + param.activation = static_cast<FuseCode>(_ctx.at(activation_index).asScalar<int32_t>()); + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index}); + auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index}); + + ::arm_compute::PoolingLayerInfo info{::arm_compute::PoolingType::L2, + ::arm_compute::Size2D{param.kw, param.kh}, + asPadStrideInfo(param.padding, param.stride)}; + + if (::internal::arm_compute::isGpuMode()) + { + std::unique_ptr<::arm_compute::CLPoolingLayer> fn{new ::arm_compute::CLPoolingLayer}; + + fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc), info); + + builder.append("L2Pool2D", std::move(fn)); + } + else + { + std::unique_ptr<::arm_compute::NEPoolingLayer> fn{new ::arm_compute::NEPoolingLayer}; + + fn->configure(ifm_alloc, ofm_alloc, info); + + builder.append("L2Pool2D", std::move(fn)); + } + + ActivationBuilder{builder}.append(param.activation, ofm_alloc); + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::EmbeddingLookup::Node &node) +{ + const ::internal::tflite::operand::Index output_index{node.param().output_index}; + const ::internal::tflite::operand::Index lookups_index{node.param().lookups_index}; + const ::internal::tflite::operand::Index values_index{node.param().values_index}; + + const auto &output_obj = _ctx.at(output_index); + const auto &lookups_obj = _ctx.at(lookups_index); + const auto &values_obj = _ctx.at(values_index); + + // Verify operand here, not at configure() to avoid acl's modifying + // TensorShape sometimes(Issue: https://github.sec.samsung.net/STAR/nnfw/issues/729) + { + assert(lookups_obj.type() == ANEURALNETWORKS_TENSOR_INT32); + + const auto &output_shape = output_obj.shape(); + const auto &lookups_shape = lookups_obj.shape(); + const auto &values_shape = values_obj.shape(); + + assert(lookups_shape.rank() == 1); + assert(values_shape.rank() >= 2); + + // output should be a n-D tensor with the same rank and shape as the values tensor, except for + // the first dimension which has the same size as lookups' only dimension. + assert(output_shape.rank() == values_shape.rank()); + assert(output_shape.dim(0) == lookups_shape.dim(0)); + for (size_t n = 1; n < output_shape.rank(); ++n) + { + assert(output_shape.dim(n) == values_shape.dim(n)); + } + } + + // Set Shape Constraints and TensorInfo + _builder.addShapeConstr(output_index, + asTensorInfo(asTensorShape(output_obj.shape(), false), output_obj.type(), + output_obj.scale(), output_obj.zeroPoint())); + _builder.addShapeConstr(lookups_index, + asTensorInfo(asTensorShape(lookups_obj.shape()), lookups_obj.type(), + lookups_obj.scale(), lookups_obj.zeroPoint())); + _builder.addShapeConstr(values_index, + asTensorInfo(asTensorShape(values_obj.shape(), false), values_obj.type(), + values_obj.scale(), values_obj.zeroPoint())); + + // Construct operation parameters + struct Param + { + int32_t output_index; + int32_t lookups_index; + int32_t values_index; + }; + + Param param; + + param.output_index = output_index.asInt(); + param.lookups_index = lookups_index.asInt(); + param.values_index = values_index.asInt(); + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.output_index}); + auto lookups_alloc = ctx.at(::internal::tflite::operand::Index{param.lookups_index}); + auto values_alloc = ctx.at(::internal::tflite::operand::Index{param.values_index}); + + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLEmbeddingLookup>(); + + fn->configure(CAST_CL(values_alloc), CAST_CL(output_alloc), CAST_CL(lookups_alloc)); + + builder.append("EmbeddingLookup", std::move(fn)); + } + else + { + // TODO Enable NEON Support + throw std::runtime_error("Not supported, yet"); + } + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::HashtableLookup::Node &node) +{ + const ::internal::tflite::operand::Index output_index{node.param().output_index}; + const ::internal::tflite::operand::Index hits_index{node.param().hits_index}; + const ::internal::tflite::operand::Index lookups_index{node.param().lookups_index}; + const ::internal::tflite::operand::Index values_index{node.param().values_index}; + const ::internal::tflite::operand::Index keys_index{node.param().keys_index}; + + const auto &lookups_obj = _ctx.at(lookups_index); + const auto &keys_obj = _ctx.at(keys_index); + const auto &hits_obj = _ctx.at(hits_index); + const auto &values_obj = _ctx.at(values_index); + const auto &output_obj = _ctx.at(output_index); + + assert(lookups_obj.type() == ANEURALNETWORKS_TENSOR_INT32); + assert(keys_obj.type() == ANEURALNETWORKS_TENSOR_INT32); + assert(hits_obj.type() == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM); + + const auto &lookups_shape = lookups_obj.shape(); + const auto &keys_shape = keys_obj.shape(); + const auto &hits_shape = hits_obj.shape(); + const auto &values_shape = values_obj.shape(); + const auto &output_shape = output_obj.shape(); + + assert(values_shape.rank() == output_shape.rank()); + + assert(lookups_shape.rank() == 1); + assert(keys_shape.rank() == 1); + assert(values_shape.dim(0) == keys_shape.dim(0)); + assert(lookups_shape.dim(0) == output_shape.dim(0)); + + _builder.addShapeConstr(output_index, + asTensorInfo(asTensorShape(_ctx.at(output_index).shape()), + _ctx.at(output_index).type(), _ctx.at(output_index).scale(), + _ctx.at(output_index).zeroPoint())); + _builder.addShapeConstr(hits_index, + asTensorInfo(asTensorShape(_ctx.at(hits_index).shape()), + _ctx.at(hits_index).type(), _ctx.at(hits_index).type(), + _ctx.at(hits_index).zeroPoint())); + + _builder.addShapeConstr(lookups_index, asTensorInfo(asTensorShape(_ctx.at(lookups_index).shape()), + _ctx.at(lookups_index).type(), + _ctx.at(lookups_index).scale(), + _ctx.at(lookups_index).zeroPoint())); + _builder.addShapeConstr(values_index, + asTensorInfo(asTensorShape(_ctx.at(values_index).shape()), + _ctx.at(values_index).type(), _ctx.at(values_index).scale(), + _ctx.at(values_index).zeroPoint())); + _builder.addShapeConstr(keys_index, + asTensorInfo(asTensorShape(_ctx.at(keys_index).shape()), + _ctx.at(keys_index).type(), _ctx.at(keys_index).scale(), + _ctx.at(keys_index).zeroPoint())); + + // Construct operation parameters + struct Param + { + int32_t output_index; + int32_t hits_index; + int32_t lookups_index; + int32_t values_index; + int32_t keys_index; + }; + + Param param; + + param.output_index = output_index.asInt(); + param.hits_index = hits_index.asInt(); + param.lookups_index = lookups_index.asInt(); + param.values_index = values_index.asInt(); + param.keys_index = keys_index.asInt(); + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.output_index}); + auto hits_alloc = ctx.at(::internal::tflite::operand::Index{param.hits_index}); + auto lookups_alloc = ctx.at(::internal::tflite::operand::Index{param.lookups_index}); + auto values_alloc = ctx.at(::internal::tflite::operand::Index{param.values_index}); + auto keys_alloc = ctx.at(::internal::tflite::operand::Index{param.keys_index}); + + if (::internal::arm_compute::isGpuMode()) // GPU + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLHashtableLookup>(); + + fn->configure(CAST_CL(lookups_alloc), CAST_CL(keys_alloc), CAST_CL(values_alloc), + CAST_CL(output_alloc), CAST_CL(hits_alloc)); + + builder.append("HashtableLookup", std::move(fn)); + } + else // NEON + { + // TODO Enable NEON Support + throw std::runtime_error("Not supported, yet"); + } + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::LocalResponseNormalization::Node &node) +{ + const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index}; + const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index}; + const ::internal::tflite::operand::Index radius_index{node.param().radius_index}; + const ::internal::tflite::operand::Index bias_index{node.param().bias_index}; + const ::internal::tflite::operand::Index alpha_index{node.param().alpha_index}; + const ::internal::tflite::operand::Index beta_index{node.param().beta_index}; + + // Set Shape Constraints and TensorInfo + _builder.addShapeConstr( + ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(), + _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint())); + _builder.addShapeConstr( + ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(), + _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint())); + + // Construct operation parameters + struct Param + { + int ofm_index; + int ifm_index; + int32_t radius; + float bias; + float alpha; + float beta; + }; + + Param param; + + param.ofm_index = ofm_index.asInt(); + param.ifm_index = ifm_index.asInt(); + + param.radius = _ctx.at(radius_index).asScalar<int32_t>(); + param.alpha = _ctx.at(alpha_index).asScalar<float>(); + param.beta = _ctx.at(beta_index).asScalar<float>(); + param.bias = _ctx.at(bias_index).asScalar<float>(); + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index}); + auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index}); + + const auto norm_info = ::arm_compute::NormalizationLayerInfo(::arm_compute::NormType::CROSS_MAP, + param.radius * 2 + 1, param.alpha, + param.beta, param.bias, false); + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLNormalizationLayer>(); + + fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc), norm_info); + + builder.append("LocalResponseNormalization", std::move(fn)); + } + else + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::NENormalizationLayer>(); + + fn->configure(ifm_alloc, ofm_alloc, norm_info); + + builder.append("LocalResponseNormalization", std::move(fn)); + } + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::DepthToSpace::Node &node) +{ + const ::internal::tflite::operand::Index output_index{node.param().output_index}; + const ::internal::tflite::operand::Index input_index{node.param().input_index}; + const ::internal::tflite::operand::Index block_size_index{node.param().block_size_index}; + + assert(_ctx.at(input_index).shape().rank() == 4); + assert(_ctx.at(output_index).shape().rank() == 4); + + int32_t block_size = _ctx.at(block_size_index).asScalar<int32_t>(); + assert(block_size > 0); + + { // assertions block + const auto output_shape = _ctx.at(output_index).shape(); + const auto input_shape = _ctx.at(input_index).shape(); + assert(output_shape.dim(0) == input_shape.dim(0)); + assert(output_shape.dim(1) == input_shape.dim(1) * block_size); + assert(output_shape.dim(2) == input_shape.dim(2) * block_size); + assert(input_shape.dim(3) % (block_size * block_size) == 0); + assert(output_shape.dim(3) == input_shape.dim(3) / (block_size * block_size)); + } + + // Set Shape Constraints and TensorInfo + _builder.addShapeConstr(output_index, + asTensorInfo(asTensorShape(_ctx.at(output_index).shape(), false), + _ctx.at(output_index).type(), _ctx.at(output_index).scale(), + _ctx.at(output_index).zeroPoint())); + _builder.addShapeConstr(input_index, + asTensorInfo(asTensorShape(_ctx.at(input_index).shape(), false), + _ctx.at(input_index).type(), _ctx.at(input_index).scale(), + _ctx.at(input_index).zeroPoint())); + + // Construct operation parameters + struct Param + { + int output_index; + int input_index; + int32_t block_size; + }; + + Param param; + + param.output_index = output_index.asInt(); + param.input_index = input_index.asInt(); + param.block_size = block_size; + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.output_index}); + auto input_alloc = ctx.at(::internal::tflite::operand::Index{param.input_index}); + + { + if (::internal::arm_compute::isGpuMode()) // GPU + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLDepthToSpace>(); + + fn->configure(CAST_CL(input_alloc), CAST_CL(output_alloc), param.block_size); + + builder.append("DepthToSpace", std::move(fn)); + } + else // NEON + { + // TODO Enable NEON Support + throw std::runtime_error("Not supported, yet"); + } + } + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::Unpack::Node &node) +{ + VERBOSE(Unpack) << "Configure Unpack operation" << std::endl; + const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index}; + uint32_t input_rank = _ctx.at(ifm_index).shape().rank(); + + assert(input_rank == 4 || input_rank == 3 || input_rank == 2); + _builder.addShapeConstr(ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), + _ctx.at(ifm_index).type())); + + int32_t axis = + _ctx.at(::internal::tflite::operand::Index{node.param().axis_index}).asScalar<int32_t>(); + // Negatige axis is supported, -1 implies R-1 axis where R is input rank + if (axis < 0) + { + axis += input_rank; + assert(axis >= 0); + } + uint32_t axis_uint = ToARMComputeAxis(input_rank, axis).value(); + // int32_t num_split = + // _ctx.at(::internal::tflite::operand::Index{node.param().num_split_index}).asScalar<int32_t>(); + + for (const auto &index : node.param().ofm_indexes) + { + const ::internal::tflite::operand::Index ofm_index{index}; + _builder.addShapeConstr(ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), + _ctx.at(ofm_index).type())); + } + + struct Param + { + std::vector<int32_t> ofm_indexes; + int ifm_index; + uint32_t axis; + }; + + if (input_rank == 4) + { + // TODO: generate test case for this and generalize 4D method all cases. + throw std::runtime_error("UNPACK_4D not implemented"); + } + else if (input_rank == 3) + { + Param param; + param.ifm_index = ifm_index.asInt(); + param.axis = axis_uint; + for (const auto &index : node.param().ofm_indexes) + { + param.ofm_indexes.push_back(index); + } + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto input_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index}); + + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLUnstack>(); + std::vector<::arm_compute::ICLTensor *> outputs; + for (const auto &index : param.ofm_indexes) + { + auto output_alloc = ctx.at(::internal::tflite::operand::Index{index}); + outputs.push_back(CAST_CL(output_alloc)); + } + fn->configure(CAST_CL(input_alloc), outputs, param.axis); + + builder.append("Unpack", std::move(fn)); + } + else + throw std::runtime_error("Not supported, yet"); + }; + + _builder.addStage(stage); + } + else if (input_rank == 2) + { + throw std::runtime_error("UNPACK_2D not implemented"); + } + else + { + throw std::runtime_error("UNPACK axis is not valid"); + } +} + +void Planner::visit(const ::internal::tflite::op::Pack::Node &node) +{ + VERBOSE(Pack) << "Configure Pack operation" << std::endl; + + const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index}; + const uint32_t output_rank = _ctx.at(ofm_index).shape().rank(); + const uint32_t input_rank = output_rank - 1; + + assert(output_rank == 4 || output_rank == 3 || output_rank == 2); + + for (const auto &index : node.param().ifm_indexes) + { + const ::internal::tflite::operand::Index ifm_index{index}; + assert(_ctx.at(ifm_index).shape().rank() == input_rank); + _builder.addShapeConstr(ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), + _ctx.at(ifm_index).type())); + } + + _builder.addShapeConstr(ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), + _ctx.at(ofm_index).type())); + + int32_t axis = + _ctx.at(::internal::tflite::operand::Index{node.param().axis_index}).asScalar<int32_t>(); + // A negative axis implies axis from the end. + // For example, axis = -1 implies the first axis from the end, i.e. axis = Rank - 1. + // Similarly, axis = -2 imples second axis from the end, i.e. axis = Rank - 2. + if (axis < 0) + { + axis += output_rank; + assert(axis >= 0); + } + uint32_t axis_uint = ToARMComputeAxis(output_rank, axis).value(); + + struct Param + { + std::vector<int32_t> ifm_indexes; + int ofm_index; + uint32_t axis; + }; + + if (input_rank == 3) + { + // TODO: generate test case for this and generalize 4D method all cases. + throw std::runtime_error("PACK_3D not implemented"); + } + else if (input_rank == 2) + { + Param param; + param.ofm_index = ofm_index.asInt(); + param.axis = axis_uint; + + for (const auto &index : node.param().ifm_indexes) + { + param.ifm_indexes.push_back(index); + } + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index}); + + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLStackLayer>(); + std::vector<::arm_compute::ICLTensor *> inputs; + for (const auto &index : param.ifm_indexes) + { + auto input_alloc = ctx.at(::internal::tflite::operand::Index{index}); + inputs.push_back(CAST_CL(input_alloc)); + } + fn->configure(inputs, param.axis, CAST_CL(output_alloc)); + + builder.append("Pack", std::move(fn)); + } + else + throw std::runtime_error("Not supported, yet"); + }; + + _builder.addStage(stage); + } + else if (input_rank == 1) + { + throw std::runtime_error("PACK_1D not implemented"); + } + else + { + throw std::runtime_error("PACK axis is not valid"); + } +} + +void Planner::visit(const ::internal::tflite::op::Neg::Node &node) +{ + const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index}; + const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index}; + + // Set Shape Constraints and TensorInfo + _builder.addShapeConstr( + ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(), + _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint())); + _builder.addShapeConstr( + ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(), + _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint())); + + // Construct operation parameters + struct Param + { + int ofm_index; + int ifm_index; + }; + + Param param; + + param.ofm_index = ofm_index.asInt(); + param.ifm_index = ifm_index.asInt(); + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index}); + auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index}); + + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLNeg>(); + + fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc)); + builder.append("Neg", std::move(fn)); + } + else + { + // TODO Enable NEON Support + throw std::runtime_error("Not supported, yet"); + } + + }; + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::Exp::Node &node) +{ + VERBOSE(Exp) << "Configure Exp operation" << std::endl; + + const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index}; + const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index}; + + // Set shape constraints + _builder.addShapeConstr( + ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(), + _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint())); + _builder.addShapeConstr( + ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(), + _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint())); + + struct Param + { + int ofm_index; + int ifm_index; + }; + + Param param; + + param.ofm_index = ofm_index.asInt(); + param.ifm_index = ifm_index.asInt(); + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index}); + auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index}); + + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLExpLayer>(); + + fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc)); + + builder.append("Exp", std::move(fn)); + } + else + { + throw std::runtime_error("Not supported"); + } + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::ReduceSum::Node &node) +{ + VERBOSE(ReduceSum) << "Configure ReduceSum operation" << std::endl; + + const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index}; + const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index}; + const ::internal::tflite::operand::Index axis_index{node.param().axis_index}; + + const auto ifm_shape = _ctx.at(ifm_index).shape(); + const auto ofm_shape = _ctx.at(ofm_index).shape(); + const auto axis_shape = _ctx.at(axis_index).shape(); + + assert(ifm_shape.rank() <= 4); + assert(ofm_shape.rank() <= ifm_shape.rank()); + assert(_ctx.at(axis_index).hasData()); + assert(axis_shape.rank() == 0 || axis_shape.rank() == 1); + + // NOTE For the 4-dimensions, if the rank of input and output are different, this runtime only + // supports cases reducing height and width or reducing depth. + // TODO We have to support all cases of dimensions up to 4. + // For correct permuting, we have to set output's shape to be equal in dimension position of the + // input. But the positions of the same dimensions in the input and output may be set differently. + // For example {2,3,4,5}(input's shape) can be reduced to {3,5}(output's shape). The original + // output shape should be {1,3,1,5}, but real output shape may be {3,5}. If you simply try to + // extend it in 4 dimensions, it should be {1,1,3,5}. + // Even if output shape is changed to {1,3,1,5}, there is another problem. It is that shape of + // output tensor used at next operation is changed to {1,3,1,5} after this operation even if the + // next operation is not desired. + if (ifm_shape.rank() == 4 && ifm_shape.rank() != ofm_shape.rank()) + { + if (ofm_shape.rank() == 2) + { + // Reducing HW + assert(ifm_shape.dim(0) == ofm_shape.dim(0) && ifm_shape.dim(3) == ofm_shape.dim(1)); + } + else if (ofm_shape.rank() == 3) + { + // Reducing C or + // (Reducing H and C(ifm and ofm) == 1) or (Reducing W and C(ifm and ofm) == 1) + assert(ifm_shape.dim(0) == ofm_shape.dim(0) && ifm_shape.dim(1) == ofm_shape.dim(1) && + ifm_shape.dim(2) == ofm_shape.dim(2) || + (ifm_shape.dim(0) == ofm_shape.dim(0) && + (ifm_shape.dim(1) == ofm_shape.dim(1) || ifm_shape.dim(2) == ofm_shape.dim(1)) && + ifm_shape.dim(3) == 1 && ofm_shape.dim(2) == 1)); + } + } + + // Set shape constraints + _builder.addShapeConstr( + ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(), + _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint())); + _builder.addShapeConstr( + ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(), + _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint())); + + uint32_t input_rank = ifm_shape.rank(); + std::set<uint32_t> axis; + int32_t axis_rank = axis_shape.rank(); + + if (axis_rank == 0) + { + int32_t axis_value = _ctx.at(axis_index).asScalar<int32_t>(); + if (axis_value < 0) + { + axis_value += input_rank; + } + axis.insert(ToARMComputeAxis(input_rank, axis_value).value()); + } + else if (axis_rank == 1) + { + const auto axis_base = _ctx.at(axis_index).data().base(); + const auto axis_size = _ctx.at(axis_index).shape().asVector(); + + // If axis's data does not exist as constant values and can be gotten as input data, we have to + // find a way to infer output shape when sinking output. + assert(axis_base != nullptr); + for (uint32_t n = 0; n < axis_size; ++n) + { + int32_t axis_value = *(reinterpret_cast<const int32_t *>(axis_base) + n); + if (axis_value < 0) + { + axis_value += input_rank; + } + axis.insert(ToARMComputeAxis(input_rank, axis_value).value()); + } + } + else + { + throw std::runtime_error("Not supported axis"); + } + + struct Param + { + int ofm_index; + int ifm_index; + std::set<uint32_t> axis; + }; + + Param param; + + param.ofm_index = ofm_index.asInt(); + param.ifm_index = ifm_index.asInt(); + param.axis = axis; + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index}); + auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index}); + + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLReduceOperation>(); + + fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc), param.axis, + ::arm_compute::ReduceOperation::SUM); + + builder.append("ReduceSum", std::move(fn)); + } + else + throw std::runtime_error("Not supported, yet"); + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::Abs::Node &node) +{ + VERBOSE(Tanh) << "Configure Abs operation" << std::endl; + + const ::internal::tflite::operand::Index output_index{node.param().output_index}; + const ::internal::tflite::operand::Index input_index{node.param().input_index}; + + // Set shape constraints + _builder.addShapeConstr(output_index, + asTensorInfo(asTensorShape(_ctx.at(output_index).shape()), + _ctx.at(output_index).type(), _ctx.at(output_index).scale(), + _ctx.at(output_index).zeroPoint())); + _builder.addShapeConstr(input_index, + asTensorInfo(asTensorShape(_ctx.at(input_index).shape()), + _ctx.at(input_index).type(), _ctx.at(output_index).scale(), + _ctx.at(output_index).zeroPoint())); + + struct Param + { + int output_index; + int input_index; + }; + + Param param; + + param.output_index = output_index.asInt(); + param.input_index = input_index.asInt(); + + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.output_index}); + auto input_alloc = ctx.at(::internal::tflite::operand::Index{param.input_index}); + + const ::arm_compute::ActivationLayerInfo act_info{ + ::arm_compute::ActivationLayerInfo::ActivationFunction::ABS}; + + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLActivationLayer>(); + + fn->configure(CAST_CL(input_alloc), CAST_CL(output_alloc), act_info); + + builder.append("Abs", std::move(fn)); + } + else + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::NEActivationLayer>(); + + fn->configure(input_alloc, output_alloc, act_info); + + builder.append("Abs", std::move(fn)); + } + }; + + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::NotEqual::Node &node) +{ + const ::internal::tflite::operand::Index output_index{node.param().output_index}; + const ::internal::tflite::operand::Index input1_index{node.param().input1_index}; + const ::internal::tflite::operand::Index input2_index{node.param().input2_index}; + + // Set Shape Constraints and TensorInfo + _builder.addShapeConstr(output_index, + asTensorInfo(asTensorShape(_ctx.at(output_index).shape()), + _ctx.at(output_index).type(), _ctx.at(output_index).scale(), + _ctx.at(output_index).zeroPoint())); + + if (!(_ctx.at(input1_index).shape() == _ctx.at(input2_index).shape())) + { + const auto broadcast_rank = + std::max(_ctx.at(input1_index).shape().rank(), _ctx.at(input2_index).shape().rank()); + const_cast<::internal::tflite::operand::Shape &>(_ctx.at(input1_index).shape()) + .extendRank(broadcast_rank); + const_cast<::internal::tflite::operand::Shape &>(_ctx.at(input2_index).shape()) + .extendRank(broadcast_rank); + } + _builder.addShapeConstr(input1_index, + asTensorInfo(asTensorShape(_ctx.at(input1_index).shape()), + _ctx.at(input1_index).type(), _ctx.at(input1_index).scale(), + _ctx.at(input1_index).zeroPoint())); + _builder.addShapeConstr(input2_index, + asTensorInfo(asTensorShape(_ctx.at(input2_index).shape()), + _ctx.at(input2_index).type(), _ctx.at(input2_index).scale(), + _ctx.at(input2_index).zeroPoint())); + + // Construct operation parameters + struct Param + { + int output_index; + int input1_index; + int input2_index; + }; + + Param param; + + param.output_index = output_index.asInt(); + param.input1_index = input1_index.asInt(); + param.input2_index = input2_index.asInt(); + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.output_index}); + auto input1_alloc = ctx.at(::internal::tflite::operand::Index{param.input1_index}); + auto input2_alloc = ctx.at(::internal::tflite::operand::Index{param.input2_index}); + + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLComparison>(); + + fn->configure(CAST_CL(input1_alloc), CAST_CL(input2_alloc), CAST_CL(output_alloc), + ::arm_compute::ComparisonOperation::NotEqual); + + builder.append("NotEqual", std::move(fn)); + } + else + { + // TODO Add NEON support + + throw std::runtime_error("Not supported yet"); + } + }; + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::LogicalAnd::Node &node) +{ + VERBOSE(Logical_AND) << "Configure Logical_AND operation" << std::endl; + + const ::internal::tflite::operand::Index output_index{node.param().output_index}; + const ::internal::tflite::operand::Index input1_index{node.param().input1_index}; + const ::internal::tflite::operand::Index input2_index{node.param().input2_index}; + + // Set Shape Constraints and TensorInfo + _builder.addShapeConstr(output_index, + asTensorInfo(asTensorShape(_ctx.at(output_index).shape()), + _ctx.at(output_index).type(), _ctx.at(output_index).scale(), + _ctx.at(output_index).zeroPoint())); + + if (!(_ctx.at(input1_index).shape() == _ctx.at(input2_index).shape())) + { + const auto broadcast_rank = + std::max(_ctx.at(input1_index).shape().rank(), _ctx.at(input2_index).shape().rank()); + const_cast<::internal::tflite::operand::Shape &>(_ctx.at(input1_index).shape()) + .extendRank(broadcast_rank); + const_cast<::internal::tflite::operand::Shape &>(_ctx.at(input2_index).shape()) + .extendRank(broadcast_rank); + } + _builder.addShapeConstr(input1_index, + asTensorInfo(asTensorShape(_ctx.at(input1_index).shape()), + _ctx.at(input1_index).type(), _ctx.at(input1_index).scale(), + _ctx.at(input1_index).zeroPoint())); + _builder.addShapeConstr(input2_index, + asTensorInfo(asTensorShape(_ctx.at(input2_index).shape()), + _ctx.at(input2_index).type(), _ctx.at(input2_index).scale(), + _ctx.at(input2_index).zeroPoint())); + + // Construct operation parameters + struct Param + { + int output_index; + int input1_index; + int input2_index; + }; + + Param param; + + param.output_index = output_index.asInt(); + param.input1_index = input1_index.asInt(); + param.input2_index = input2_index.asInt(); + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.output_index}); + auto input1_alloc = ctx.at(::internal::tflite::operand::Index{param.input1_index}); + auto input2_alloc = ctx.at(::internal::tflite::operand::Index{param.input2_index}); + + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLBinaryLogicalOp>(); + + fn->configure(CAST_CL(input1_alloc), CAST_CL(input2_alloc), CAST_CL(output_alloc), + ::arm_compute::BinaryLogicalOperation::AND); + + builder.append("LogicalAnd", std::move(fn)); + } + else + { + // TODO Add NEON support + + throw std::runtime_error("Not supported yet"); + } + }; + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::LogicalNot::Node &node) +{ + const ::internal::tflite::operand::Index output_index{node.param().output_index}; + const ::internal::tflite::operand::Index input_index{node.param().input_index}; + + // Set Shape Constraints and TensorInfo + _builder.addShapeConstr(output_index, + asTensorInfo(asTensorShape(_ctx.at(output_index).shape()), + ::arm_compute::DataType::U8, _ctx.at(output_index).scale(), + _ctx.at(output_index).zeroPoint())); + + _builder.addShapeConstr(input_index, + asTensorInfo(asTensorShape(_ctx.at(input_index).shape()), + ::arm_compute::DataType::U8, _ctx.at(input_index).scale(), + _ctx.at(input_index).zeroPoint())); + + // Construct operation parameters + struct Param + { + int output_index; + int input_index; + }; + + Param param; + + param.output_index = output_index.asInt(); + param.input_index = input_index.asInt(); + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.output_index}); + auto input_alloc = ctx.at(::internal::tflite::operand::Index{param.input_index}); + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLBitwiseNot>(); + + fn->configure(CAST_CL(input_alloc), CAST_CL(output_alloc)); + + builder.append("LogicalNot", std::move(fn)); + } + else + { + // TODO Add NEON support + + throw std::runtime_error("Not supported yet"); + } + }; + _builder.addStage(stage); +} + +void Planner::visit(const ::internal::tflite::op::LogicalOr::Node &node) +{ + VERBOSE(LogicalOr) << "Configure LogicalOr operation" << std::endl; + + const ::internal::tflite::operand::Index output_index{node.param().output_index}; + const ::internal::tflite::operand::Index input1_index{node.param().input1_index}; + const ::internal::tflite::operand::Index input2_index{node.param().input2_index}; + + // Set Shape Constraints and TensorInfo + _builder.addShapeConstr(output_index, + asTensorInfo(asTensorShape(_ctx.at(output_index).shape()), + _ctx.at(output_index).type(), _ctx.at(output_index).scale(), + _ctx.at(output_index).zeroPoint())); + + if (!(_ctx.at(input1_index).shape() == _ctx.at(input2_index).shape())) + { + const auto broadcast_rank = + std::max(_ctx.at(input1_index).shape().rank(), _ctx.at(input2_index).shape().rank()); + const_cast<::internal::tflite::operand::Shape &>(_ctx.at(input1_index).shape()) + .extendRank(broadcast_rank); + const_cast<::internal::tflite::operand::Shape &>(_ctx.at(input2_index).shape()) + .extendRank(broadcast_rank); + } + + _builder.addShapeConstr(input1_index, + asTensorInfo(asTensorShape(_ctx.at(input1_index).shape()), + _ctx.at(input1_index).type(), _ctx.at(input1_index).scale(), + _ctx.at(input1_index).zeroPoint())); + _builder.addShapeConstr(input2_index, + asTensorInfo(asTensorShape(_ctx.at(input2_index).shape()), + _ctx.at(input2_index).type(), _ctx.at(input2_index).scale(), + _ctx.at(input2_index).zeroPoint())); + + // Construct operation parameters + struct Param + { + int output_index; + int input1_index; + int input2_index; + }; + + Param param; + + param.output_index = output_index.asInt(); + param.input1_index = input1_index.asInt(); + param.input2_index = input2_index.asInt(); + auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) { + auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.output_index}); + auto input1_alloc = ctx.at(::internal::tflite::operand::Index{param.input1_index}); + auto input2_alloc = ctx.at(::internal::tflite::operand::Index{param.input2_index}); + if (::internal::arm_compute::isGpuMode()) + { + auto fn = nnfw::cpp14::make_unique<::arm_compute::CLBinaryLogicalOp>(); + + fn->configure(CAST_CL(input1_alloc), CAST_CL(input2_alloc), CAST_CL(output_alloc), + ::arm_compute::BinaryLogicalOperation::OR); + + builder.append("LogicalOr", std::move(fn)); + } + else + { + // TODO Add NEON support + + throw std::runtime_error("Not supported yet"); + } + }; + _builder.addStage(stage); +} + +class AllocationContext final : public IAllocationContext +{ +public: + AllocationContext(::internal::arm_compute::Plan &plan) : _plan{plan} + { + // DO NOTHING + } + +public: + ::arm_compute::ITensor *at(const ::internal::tflite::operand::Index &ind) const override + { + return _plan.operands().at(ind).ptr(); + } + +private: + ::internal::arm_compute::Plan &_plan; +}; + +class ExecutionBuilder final : public IExecutionBuilder +{ +public: + ExecutionBuilder(::internal::arm_compute::Plan &plan) : _plan{plan} + { + // DO NOTHING + } + +public: + void append(const std::string &name, std::unique_ptr<::arm_compute::IFunction> &&f) override + { + _plan.operations().append(std::move(f)); + _plan.operations().at(_plan.operations().size() - 1).name() = name; + } + +#ifdef TFLITE_PROFILING_ENABLED +public: + int plan_op_size() const { return _plan.operations().size(); } + void addOpIndexToSteps(int from, int to, int op_idx) + { + for (int i = from; i < to; ++i) + _plan.operations().at(i).op_idx() = op_idx; + } +#endif + +private: + ::internal::arm_compute::Plan &_plan; +}; + +/** + * @brief Class to provide methods of compilation plan builder + */ +class PlanBuilder final : public IPlanBuilder +{ +public: + /** + * @brief Construct a new PlanBuilder object with Plan + * @param [in] plan The Plan object + */ + PlanBuilder(::internal::arm_compute::Plan &plan) : _plan{plan} + { + // DO NOTHING + } + +public: + /** + * @brief Add TensorInfo with Shape Constraints + * @param [in] ind Index of operand + * @param [in] info TensorInfo value to set to index of operand + * @return N/A + */ + void addShapeConstr(const ::internal::tflite::operand::Index &ind, + const ::arm_compute::TensorInfo &info) override; + +public: + /** + * @brief Add Subsumption constraints + * @param [in] ind Index of operand + * @param [in] base Index of base operand of Subsumption + * @param [in] offset Offset of Subsumption + * @param [in] shape Shape of Subsumption + * @param [in] extend_parent extend_parent value of Subsumption + * @return N/A + */ + void addSubsumptionConstr(const ::internal::tflite::operand::Index &ind, + const ::internal::tflite::operand::Index &base, + const ::arm_compute::Coordinates &offset, + const ::arm_compute::TensorShape &shape, bool extend_parent) override; + +public: + /** + * @brief Add Initializer lambda with ITensor param + * @param [in] ind Index of operand + * @param [in] initializer Initializer to add + * @return N/A + */ + void addInitializer(const ::internal::tflite::operand::Index &ind, + const Initializer &initializer) override; + +public: + /** + * @brief Add Stage lambda with IAllocationContext and IExecutionBuilder params + * @param [in] stage Stage to add + * @return N/A + */ + void addStage(const Stage &stage) override; + +public: + /** + * @brief Finilize(build) the Plan + * @return N/A + */ + void finalize(void) const; + +private: + ::internal::arm_compute::Plan &_plan; + +private: + struct Subsumption + { + public: + Subsumption(const ::internal::tflite::operand::Index &base, + const ::arm_compute::Coordinates &offset, const ::arm_compute::TensorShape &shape, + bool extend_parent) + : _base{base}, _offset{offset}, _shape{shape}, _extend_parent{extend_parent} + { + // DO NOTHING + } + + public: + const ::internal::tflite::operand::Index &base(void) const { return _base; } + const ::arm_compute::Coordinates &offset(void) const { return _offset; } + const ::arm_compute::TensorShape &shape(void) const { return _shape; } + const bool extend_parent(void) const { return _extend_parent; } + + private: + const ::internal::tflite::operand::Index _base; + const ::arm_compute::Coordinates _offset; + const ::arm_compute::TensorShape _shape; + const bool _extend_parent; + }; + +private: + std::map<int, ::arm_compute::TensorInfo> _tensor_info_ctx; + std::map<int, std::shared_ptr<Subsumption>> _subsumption_ctx; + std::map<int, Initializer> _initializer_ctx; + std::vector<Stage> _stages; +}; + +void PlanBuilder::addShapeConstr(const ::internal::tflite::operand::Index &ind, + const ::arm_compute::TensorInfo &info) +{ + _tensor_info_ctx[ind.asInt()] = info; +} + +void PlanBuilder::addSubsumptionConstr(const ::internal::tflite::operand::Index &ind, + const ::internal::tflite::operand::Index &base, + const ::arm_compute::Coordinates &offset, + const ::arm_compute::TensorShape &shape, bool extend_parent) +{ + _subsumption_ctx[ind.asInt()] = std::make_shared<Subsumption>(base, offset, shape, extend_parent); +} + +void PlanBuilder::addInitializer(const ::internal::tflite::operand::Index &ind, + const Initializer &initializer) +{ + _initializer_ctx[ind.asInt()] = initializer; +} + +void PlanBuilder::addStage(const Stage &stage) { _stages.emplace_back(stage); } + +#include <stack> + +void PlanBuilder::finalize(void) const +{ + // ITensor objects to be initialized later + std::vector<std::shared_ptr<::arm_compute::ITensor>> tensors; + + // Create Tensor & CLSubTensor + auto isAllocated = [this](int ind) { + const ::internal::tflite::operand::Index operand_index{ind}; + return _plan.operands().exist(operand_index); + }; + + auto setCLTensor = [&](int ind) { + auto tensor = std::make_shared<::arm_compute::CLTensor>(); + + tensor->allocator()->init(_tensor_info_ctx.at(ind)); + + // NOTE Do NOT allocate here. allocate should be invoked after configure functions + _plan.operands().set(::internal::tflite::operand::Index{ind}, tensor); + tensors.emplace_back(tensor); + }; + + auto setCLSubTensor = [&](int curr) { + const auto &sub_info = *(_subsumption_ctx.find(curr)->second); + + auto base_tensor = _plan.operands().at(sub_info.base()).ptr(); + + assert(base_tensor != nullptr); + + auto curr_tensor = std::make_shared<::arm_compute::CLSubTensor>( + CAST_CL(base_tensor), sub_info.shape(), sub_info.offset(), sub_info.extend_parent()); + + _plan.operands().set(::internal::tflite::operand::Index{curr}, curr_tensor); + }; + + auto setNETensor = [&](int ind) { + auto tensor = std::make_shared<::arm_compute::Tensor>(); + + tensor->allocator()->init(_tensor_info_ctx.at(ind)); + + // NOTE Do NOT allocate here. allocate should be invoked after configure functions + _plan.operands().set(::internal::tflite::operand::Index{ind}, tensor); + tensors.emplace_back(tensor); + }; + + auto setNESubTensor = [&](int curr) { + const auto &sub_info = *(_subsumption_ctx.find(curr)->second); + + auto base_tensor = _plan.operands().at(sub_info.base()).ptr(); + + assert(base_tensor != nullptr); + + auto curr_tensor = std::make_shared<::arm_compute::SubTensor>(base_tensor, sub_info.shape(), + sub_info.offset()); + + _plan.operands().set(::internal::tflite::operand::Index{curr}, curr_tensor); + }; + + for (auto it = _subsumption_ctx.begin(); it != _subsumption_ctx.end(); ++it) + { + std::stack<int> stack; + + stack.push(it->first); + + while (!stack.empty()) + { + const auto curr = stack.top(); + + if (isAllocated(curr)) + { + // Skip if already allocated + stack.pop(); + continue; + } + + auto it_s = _subsumption_ctx.find(curr); + + if (it_s == _subsumption_ctx.end()) + { + if (::internal::arm_compute::isGpuMode()) + setCLTensor(curr); + else + setNETensor(curr); + stack.pop(); + continue; + } + + const auto &sub_info = *(it_s->second); + + if (isAllocated(sub_info.base().asInt())) + { + if (::internal::arm_compute::isGpuMode()) + setCLSubTensor(curr); + else + setNESubTensor(curr); + stack.pop(); + } + else + { + // Allocate base tensor first + stack.push(sub_info.base().asInt()); + } + } + } + + for (auto it = _tensor_info_ctx.begin(); it != _tensor_info_ctx.end(); ++it) + { + if (isAllocated(it->first)) + { + // Skip if already allocated + continue; + } + + if (::internal::arm_compute::isGpuMode()) + setCLTensor(it->first); + else + setNETensor(it->first); + } + + // Process Stage + AllocationContext allocation_context{_plan}; + ExecutionBuilder execution_builder{_plan}; + + for (int idx = 0; idx < _stages.size(); idx++) + { + const auto &stage = _stages[idx]; +#ifdef TFLITE_PROFILING_ENABLED + int from = execution_builder.plan_op_size(); +#endif + stage(allocation_context, execution_builder); +#ifdef TFLITE_PROFILING_ENABLED + int to = execution_builder.plan_op_size(); + execution_builder.addOpIndexToSteps(from, to, idx); +#endif + } + + // Allocate Tensor Memory + for (const auto &tensor : tensors) + { + if (::internal::arm_compute::isGpuMode()) + { + auto cl_tensor = CAST_CL(tensor.get()); + cl_tensor->allocator()->allocate(); + } + else + { + auto ne_tensor = CAST_NE(tensor.get()); + ne_tensor->allocator()->allocate(); + } + } + + // Fill weight/bias + for (auto it = _initializer_ctx.begin(); it != _initializer_ctx.end(); ++it) + { + const ::internal::tflite::operand::Index operand_index{it->first}; + _plan.operands().at(operand_index).access(it->second); + } + + // Initialize CLTensors that have data in their corresponding NNAPI operand but are not + // initialized yet + const auto &operands = _plan.model().operands(); + for (int idx = 0; idx < operands.size(); ++idx) + { + const ::internal::tflite::operand::Index operand_idx{idx}; + if (isAllocated(idx) && operands.at(operand_idx).hasData() && + _initializer_ctx.find(idx) == _initializer_ctx.end()) + { + auto rank = operands.at(operand_idx).shape().rank(); + auto base = operands.at(operand_idx).data().base(); + auto type = operands.at(operand_idx).type(); + auto shape = operands.at(operand_idx).shape(); + + // Need to support scalar types (ANEURALNETWORKS_FLOAT32 and ANEURALNETWORKS_INT32) + // for rank > 1 tensor, because it can be operand of broadcast operation + switch (rank) + { + case 0: // scalar + { + switch (type) + { + case ANEURALNETWORKS_FLOAT32: + case ANEURALNETWORKS_TENSOR_FLOAT32: + { + auto initializer = std::bind(initVectorTensor<float>, _1, base, 1); + _plan.operands().at(operand_idx).access(initializer); + break; + } + case ANEURALNETWORKS_INT32: + case ANEURALNETWORKS_TENSOR_INT32: + { + auto initializer = std::bind(initVectorTensor<int32_t>, _1, base, 1); + _plan.operands().at(operand_idx).access(initializer); + break; + } + case ANEURALNETWORKS_UINT32: + { + auto initializer = std::bind(initVectorTensor<uint32_t>, _1, base, 1); + _plan.operands().at(operand_idx).access(initializer); + break; + } + case ANEURALNETWORKS_TENSOR_QUANT8_ASYMM: + { + auto initializer = std::bind(initVectorTensor<uint8_t>, _1, base, 1); + _plan.operands().at(operand_idx).access(initializer); + break; + } + default: + throw std::runtime_error("Unknown scalar type, type : " + std::to_string(type)); + break; + } + break; + } + case 1: // vector + { + auto size = shape.asVector(); + switch (type) + { + case ANEURALNETWORKS_FLOAT32: + case ANEURALNETWORKS_TENSOR_FLOAT32: + { + auto initializer = std::bind(initVectorTensor<float>, _1, base, size); + _plan.operands().at(operand_idx).access(initializer); + break; + } + case ANEURALNETWORKS_INT32: + case ANEURALNETWORKS_TENSOR_INT32: + { + auto initializer = std::bind(initVectorTensor<int32_t>, _1, base, size); + _plan.operands().at(operand_idx).access(initializer); + break; + } + case ANEURALNETWORKS_TENSOR_QUANT8_ASYMM: + { + auto initializer = std::bind(initVectorTensor<uint8_t>, _1, base, size); + _plan.operands().at(operand_idx).access(initializer); + break; + } + default: + throw std::runtime_error("Unknown tensor type, type : " + std::to_string(type)); + break; + } + break; + } + case 2: // matrix + { + const auto matrix_shape = shape.asMatrix(); + auto size = operands.at(operand_idx).data().size(); + switch (type) + { + case ANEURALNETWORKS_FLOAT32: + case ANEURALNETWORKS_TENSOR_FLOAT32: + { + auto initializer = std::bind(initMatrixTensor<float>, _1, matrix_shape, base, size); + _plan.operands().at(operand_idx).access(initializer); + break; + } + case ANEURALNETWORKS_INT32: + case ANEURALNETWORKS_TENSOR_INT32: + { + auto initializer = std::bind(initMatrixTensor<int32_t>, _1, matrix_shape, base, size); + _plan.operands().at(operand_idx).access(initializer); + break; + } + case ANEURALNETWORKS_TENSOR_QUANT8_ASYMM: + { + auto initializer = std::bind(initMatrixTensor<uint8_t>, _1, matrix_shape, base, size); + _plan.operands().at(operand_idx).access(initializer); + break; + } + default: + throw std::runtime_error("Unknown tensor type, type : " + std::to_string(type)); + break; + } + break; + } + case 3: // 3D tensor + { + const auto tensor_shape = shape.asTensor(); + auto size = operands.at(operand_idx).data().size(); + switch (type) + { + case ANEURALNETWORKS_FLOAT32: + case ANEURALNETWORKS_TENSOR_FLOAT32: + { + auto initializer = std::bind(initTensor3D<float>, _1, tensor_shape, base, size); + _plan.operands().at(operand_idx).access(initializer); + break; + } + case ANEURALNETWORKS_INT32: + case ANEURALNETWORKS_TENSOR_INT32: + { + auto initializer = std::bind(initTensor3D<int32_t>, _1, tensor_shape, base, size); + _plan.operands().at(operand_idx).access(initializer); + break; + } + case ANEURALNETWORKS_TENSOR_QUANT8_ASYMM: + { + auto initializer = std::bind(initTensor3D<uint8_t>, _1, tensor_shape, base, size); + _plan.operands().at(operand_idx).access(initializer); + break; + } + default: + throw std::runtime_error("Unknown tensor type, type : " + std::to_string(type)); + break; + } + break; + } + case 4: // feature + { + const auto feature_shape = shape.asFeature(); + auto size = operands.at(operand_idx).data().size(); + switch (type) + { + case ANEURALNETWORKS_FLOAT32: + case ANEURALNETWORKS_TENSOR_FLOAT32: + { + auto initializer = std::bind(initFeatureTensor<float>, _1, feature_shape, base, size); + _plan.operands().at(operand_idx).access(initializer); + break; + } + case ANEURALNETWORKS_INT32: + case ANEURALNETWORKS_TENSOR_INT32: + { + auto initializer = + std::bind(initFeatureTensor<int32_t>, _1, feature_shape, base, size); + _plan.operands().at(operand_idx).access(initializer); + break; + } + case ANEURALNETWORKS_TENSOR_QUANT8_ASYMM: + { + auto initializer = + std::bind(initFeatureTensor<uint8_t>, _1, feature_shape, base, size); + _plan.operands().at(operand_idx).access(initializer); + break; + } + default: + throw std::runtime_error("Unknown tensor type, type : " + std::to_string(type)); + break; + } + break; + } + default: + throw std::runtime_error("Not supported, yet"); + break; + } + } + } +} + +// +// NNAPI Implementation +// +int ANeuralNetworksCompilation_create(ANeuralNetworksModel *model, + ANeuralNetworksCompilation **compilation) +{ + if ((model == nullptr) || (compilation == nullptr)) + { + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + if (!model->isFinished()) + { + return ANEURALNETWORKS_BAD_STATE; + } + + std::shared_ptr<const internal::tflite::Model> internal; + + model->release(internal); + + ANeuralNetworksCompilation *compilation_ptr = new ANeuralNetworksCompilation(internal); + if (compilation_ptr == nullptr) + { + return ANEURALNETWORKS_OUT_OF_MEMORY; + } + *compilation = compilation_ptr; + + return ANEURALNETWORKS_NO_ERROR; +} + +int ANeuralNetworksCompilation_setPreference(ANeuralNetworksCompilation *compilation, + int32_t preference) +{ + if (compilation == nullptr) + { + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + // NOTE Pure CL runimte currently ignores this API call + // TODO Use preference + return ANEURALNETWORKS_NO_ERROR; +} + +int ANeuralNetworksCompilation_finish(ANeuralNetworksCompilation *compilation) +{ + if (compilation == nullptr) + { + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + if (::internal::arm_compute::isGpuMode()) + { + arm_compute::CLScheduler::get().default_init(); + // NOTE CLKernelLibraryEx must use the same context as CLScheduler + // It did not check whether another device is available. + arm_compute::CLKernelLibraryEx::get().init( + "./cl_kernels/", arm_compute::CLScheduler::get().context(), cl::Device::getDefault()); + } + + const auto &operands = compilation->plan().model().operands(); + const auto &operations = compilation->plan().model().operations(); + + PlanBuilder plan_builder{compilation->plan()}; + + for (uint32_t n = 0; n < operations.size(); ++n) + { + operations.at(n).accept(Planner{operands, plan_builder}); + } + + plan_builder.finalize(); + + return ANEURALNETWORKS_NO_ERROR; +} + +void ANeuralNetworksCompilation_free(ANeuralNetworksCompilation *compilation) +{ + delete compilation; +} diff --git a/runtime/contrib/pure_arm_compute/src/compilation.h b/runtime/contrib/pure_arm_compute/src/compilation.h new file mode 100644 index 000000000..1a06d06b9 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/compilation.h @@ -0,0 +1,75 @@ +/* + * 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. + */ + +/** + * @file compilation.h + * @brief This file defines ANeuralNetworksCompilation class for handling Compilation NNAPI + * @ingroup COM_AI_RUNTIME + */ + +#ifndef __COMPILATION_H__ +#define __COMPILATION_H__ + +#include "internal/Model.h" +#include "internal/arm_compute.h" + +/** + * @brief struct to define Compilation of NNAPI + */ +struct ANeuralNetworksCompilation +{ +public: + /** + * @brief Construct with params + * @param [in] model Pointer of internal::tflite::Model to set internal::arm_compute::Plan + */ + ANeuralNetworksCompilation(const std::shared_ptr<const internal::tflite::Model> &model) + : _plan{new internal::arm_compute::Plan{model}} + { + // DO NOTHING + } + +public: + /** + * @brief Get reference of internal::arm_compute::Plan + * @return Reference of internal::arm_compute::Plan + */ + internal::arm_compute::Plan &plan(void) { return *_plan; } + +public: + /** + * @brief Publish internal Plan to param + * @param [out] plan Pointer of internal::arm_compute::Plan to be set + * @return N/A + */ + void publish(std::shared_ptr<const internal::arm_compute::Plan> &plan) { plan = _plan; } + /** + * @brief Get @c true if ANeuralNetworksCompilation_finish has been called, otherwise @c false + * @return @c true if ANeuralNetworksCompilation_finish has been called, otherwise @c false + */ + bool isFinished(void) { return _isFinished; } + /** + * @brief Mark compilation process finished + * @return N/A + */ + void markAsFinished() { _isFinished = true; } + +private: + std::shared_ptr<internal::arm_compute::Plan> _plan; + bool _isFinished{false}; +}; + +#endif diff --git a/runtime/contrib/pure_arm_compute/src/event.cc b/runtime/contrib/pure_arm_compute/src/event.cc new file mode 100644 index 000000000..247586cc3 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/event.cc @@ -0,0 +1,31 @@ +/* + * 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 <NeuralNetworks.h> + +#include "event.h" + +int ANeuralNetworksEvent_wait(ANeuralNetworksEvent *event) +{ + if (event == nullptr) + { + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + return ANEURALNETWORKS_NO_ERROR; +} + +void ANeuralNetworksEvent_free(ANeuralNetworksEvent *event) { delete event; } diff --git a/runtime/contrib/pure_arm_compute/src/event.h b/runtime/contrib/pure_arm_compute/src/event.h new file mode 100644 index 000000000..b5595583c --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/event.h @@ -0,0 +1,33 @@ +/* + * 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. + */ + +/** + * @file event.h + * @brief This file defines ANeuralNetworksEvent struct for handling Event NNAPI + * @ingroup COM_AI_RUNTIME + */ + +#ifndef __EVENT_H__ +#define __EVENT_H__ + +/** + * @brief struct to define Event of NNAPI + */ +struct ANeuralNetworksEvent +{ +}; + +#endif diff --git a/runtime/contrib/pure_arm_compute/src/execution.cc b/runtime/contrib/pure_arm_compute/src/execution.cc new file mode 100644 index 000000000..657d25288 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/execution.cc @@ -0,0 +1,628 @@ +/* + * 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 <NeuralNetworks.h> + +#include "compilation.h" +#include "execution.h" +#include "profiling/profiling.h" +#include "profiling/profiler.h" +#include "event.h" + +#include "internal/VectorSource.h" +#include "internal/MatrixSource.h" +#include "internal/Tensor3DSource.h" +#include "internal/FeatureSource.h" +#include "internal/TensorSource.h" + +#include "internal/Sinks.h" +#include "internal/VectorSink.h" +#include "internal/MatrixSink.h" +#include "internal/Tensor3DSink.h" +#include "internal/FeatureSink.h" + +#include "misc/feature/IndexIterator.h" + +#include <arm_compute/runtime/CL/CLScheduler.h> + +#include <cassert> + +static void asVectorSource(ANeuralNetworksExecution *execution, int32_t type, int32_t index, + int32_t len, const void *buffer, size_t length) +{ + switch (type) + { + case ANEURALNETWORKS_FLOAT32: + case ANEURALNETWORKS_TENSOR_FLOAT32: + execution->source<VectorSource<float>>(index, len, reinterpret_cast<const float *>(buffer), + length); + break; + case ANEURALNETWORKS_INT32: + case ANEURALNETWORKS_TENSOR_INT32: + execution->source<VectorSource<int32_t>>(index, len, + reinterpret_cast<const int32_t *>(buffer), length); + break; + case ANEURALNETWORKS_UINT32: + execution->source<VectorSource<uint32_t>>(index, len, + reinterpret_cast<const uint32_t *>(buffer), length); + break; + case ANEURALNETWORKS_TENSOR_QUANT8_ASYMM: + execution->source<VectorSource<uint8_t>>(index, len, + reinterpret_cast<const uint8_t *>(buffer), length); + break; + default: + throw std::runtime_error("Not supported, yet"); + break; + } +} + +static void asMatrixSource(ANeuralNetworksExecution *execution, int32_t type, int32_t index, + const nnfw::misc::matrix::Shape &shape, const void *buffer, + size_t length) +{ + switch (type) + { + case ANEURALNETWORKS_FLOAT32: + case ANEURALNETWORKS_TENSOR_FLOAT32: + execution->source<MatrixSource<float>>(index, shape, reinterpret_cast<const float *>(buffer), + length); + break; + case ANEURALNETWORKS_INT32: + case ANEURALNETWORKS_TENSOR_INT32: + execution->source<MatrixSource<int32_t>>(index, shape, + reinterpret_cast<const int32_t *>(buffer), length); + break; + case ANEURALNETWORKS_UINT32: + execution->source<MatrixSource<uint32_t>>(index, shape, + reinterpret_cast<const uint32_t *>(buffer), length); + break; + case ANEURALNETWORKS_TENSOR_QUANT8_ASYMM: + execution->source<MatrixSource<uint8_t>>(index, shape, + reinterpret_cast<const uint8_t *>(buffer), length); + break; + default: + throw std::runtime_error("Not supported, yet"); + break; + } +} + +static void asTensor3DSource(ANeuralNetworksExecution *execution, int32_t type, int32_t index, + const nnfw::misc::tensor::Shape &shape, const void *buffer, + size_t length) +{ + switch (type) + { + case ANEURALNETWORKS_FLOAT32: + case ANEURALNETWORKS_TENSOR_FLOAT32: + execution->source<Tensor3DSource<float>>(index, shape, + reinterpret_cast<const float *>(buffer), length); + break; + case ANEURALNETWORKS_INT32: + case ANEURALNETWORKS_TENSOR_INT32: + execution->source<Tensor3DSource<int32_t>>(index, shape, + reinterpret_cast<const int32_t *>(buffer), length); + break; + case ANEURALNETWORKS_UINT32: + execution->source<Tensor3DSource<uint32_t>>( + index, shape, reinterpret_cast<const uint32_t *>(buffer), length); + break; + case ANEURALNETWORKS_TENSOR_QUANT8_ASYMM: + execution->source<Tensor3DSource<uint8_t>>(index, shape, + reinterpret_cast<const uint8_t *>(buffer), length); + break; + default: + throw std::runtime_error("Not supported, yet"); + break; + } +} + +static void asTensorSource(ANeuralNetworksExecution *execution, int32_t type, int32_t index, + const nnfw::misc::tensor::Shape &shape, const void *buffer, + size_t length) +{ + switch (type) + { + case ANEURALNETWORKS_FLOAT32: + case ANEURALNETWORKS_TENSOR_FLOAT32: + execution->source<TensorSource<float>>(index, shape, reinterpret_cast<const float *>(buffer), + length); + break; + case ANEURALNETWORKS_INT32: + case ANEURALNETWORKS_TENSOR_INT32: + execution->source<TensorSource<int32_t>>(index, shape, + reinterpret_cast<const int32_t *>(buffer), length); + break; + case ANEURALNETWORKS_UINT32: + execution->source<TensorSource<uint32_t>>(index, shape, + reinterpret_cast<const uint32_t *>(buffer), length); + break; + case ANEURALNETWORKS_TENSOR_QUANT8_ASYMM: + execution->source<TensorSource<uint8_t>>(index, shape, + reinterpret_cast<const uint8_t *>(buffer), length); + break; + default: + throw std::runtime_error("Not supported, yet"); + break; + } +} + +static void asFeatureSource(ANeuralNetworksExecution *execution, int32_t type, int32_t index, + const nnfw::misc::feature::Shape &shape, const void *buffer, + size_t length) +{ + switch (type) + { + case ANEURALNETWORKS_FLOAT32: + case ANEURALNETWORKS_TENSOR_FLOAT32: + execution->source<FeatureSource<float>>(index, shape, reinterpret_cast<const float *>(buffer), + length); + break; + case ANEURALNETWORKS_INT32: + case ANEURALNETWORKS_TENSOR_INT32: + execution->source<FeatureSource<int32_t>>(index, shape, + reinterpret_cast<const int32_t *>(buffer), length); + break; + case ANEURALNETWORKS_UINT32: + execution->source<FeatureSource<uint32_t>>( + index, shape, reinterpret_cast<const uint32_t *>(buffer), length); + break; + case ANEURALNETWORKS_TENSOR_QUANT8_ASYMM: + execution->source<FeatureSource<uint8_t>>(index, shape, + reinterpret_cast<const uint8_t *>(buffer), length); + break; + default: + throw std::runtime_error("Not supported, yet"); + break; + } +} + +static void asVectorSink(ANeuralNetworksExecution *execution, int32_t type, int32_t index, + int32_t len, void *buffer, size_t length) +{ + switch (type) + { + case ANEURALNETWORKS_FLOAT32: + case ANEURALNETWORKS_TENSOR_FLOAT32: + execution->sink<VectorSink<float>>(index, len, reinterpret_cast<float *>(buffer), length); + break; + case ANEURALNETWORKS_INT32: + case ANEURALNETWORKS_TENSOR_INT32: + execution->sink<VectorSink<int32_t>>(index, len, reinterpret_cast<int32_t *>(buffer), length); + break; + case ANEURALNETWORKS_UINT32: + execution->sink<VectorSink<uint32_t>>(index, len, reinterpret_cast<uint32_t *>(buffer), + length); + break; + case ANEURALNETWORKS_TENSOR_QUANT8_ASYMM: + execution->sink<VectorSink<uint8_t>>(index, len, reinterpret_cast<uint8_t *>(buffer), length); + break; + default: + throw std::runtime_error("Not supported, yet"); + break; + } +} + +static void asMatrixSink(ANeuralNetworksExecution *execution, int32_t type, int32_t index, + int32_t H, int32_t W, void *buffer, size_t length) +{ + switch (type) + { + case ANEURALNETWORKS_FLOAT32: + case ANEURALNETWORKS_TENSOR_FLOAT32: + execution->sink<MatrixSink<float>>(index, H, W, reinterpret_cast<float *>(buffer), length); + break; + case ANEURALNETWORKS_INT32: + case ANEURALNETWORKS_TENSOR_INT32: + execution->sink<MatrixSink<int32_t>>(index, H, W, reinterpret_cast<int32_t *>(buffer), + length); + break; + case ANEURALNETWORKS_UINT32: + execution->sink<MatrixSink<uint32_t>>(index, H, W, reinterpret_cast<uint32_t *>(buffer), + length); + break; + case ANEURALNETWORKS_TENSOR_QUANT8_ASYMM: + execution->sink<MatrixSink<uint8_t>>(index, H, W, reinterpret_cast<uint8_t *>(buffer), + length); + break; + default: + throw std::runtime_error("Not supported, yet"); + break; + } +} + +static void asFeatureSink(ANeuralNetworksExecution *execution, int32_t type, int32_t index, + const nnfw::misc::feature::Shape &shape, void *buffer, size_t length) +{ + switch (type) + { + case ANEURALNETWORKS_FLOAT32: + case ANEURALNETWORKS_TENSOR_FLOAT32: + execution->sink<FeatureSink<float>>(index, shape, reinterpret_cast<float *>(buffer), length); + break; + case ANEURALNETWORKS_INT32: + case ANEURALNETWORKS_TENSOR_INT32: + execution->sink<FeatureSink<int32_t>>(index, shape, reinterpret_cast<int32_t *>(buffer), + length); + break; + case ANEURALNETWORKS_UINT32: + execution->sink<FeatureSink<uint32_t>>(index, shape, reinterpret_cast<uint32_t *>(buffer), + length); + break; + case ANEURALNETWORKS_TENSOR_QUANT8_ASYMM: + execution->sink<FeatureSink<uint8_t>>(index, shape, reinterpret_cast<uint8_t *>(buffer), + length); + break; + default: + throw std::runtime_error("Not supported, yet"); + break; + } +} + +static void asTensor3DSink(ANeuralNetworksExecution *execution, int32_t type, int32_t index, + const nnfw::misc::tensor::Shape &shape, void *buffer, size_t length) +{ + assert(shape.rank() == 3); + + switch (type) + { + case ANEURALNETWORKS_FLOAT32: + case ANEURALNETWORKS_TENSOR_FLOAT32: + execution->sink<Tensor3DSink<float>>(index, shape, reinterpret_cast<float *>(buffer), length); + break; + case ANEURALNETWORKS_INT32: + case ANEURALNETWORKS_TENSOR_INT32: + execution->sink<Tensor3DSink<int32_t>>(index, shape, reinterpret_cast<int32_t *>(buffer), + length); + break; + case ANEURALNETWORKS_UINT32: + execution->sink<Tensor3DSink<uint32_t>>(index, shape, reinterpret_cast<uint32_t *>(buffer), + length); + break; + case ANEURALNETWORKS_TENSOR_QUANT8_ASYMM: + execution->sink<Tensor3DSink<uint8_t>>(index, shape, reinterpret_cast<uint8_t *>(buffer), + length); + break; + default: + throw std::runtime_error("Not supported, yet"); + break; + } +} + +static void asTensorSink(ANeuralNetworksExecution *execution, int32_t type, int32_t index, + const nnfw::misc::tensor::Shape &shape, void *buffer, size_t length) +{ + switch (type) + { + case ANEURALNETWORKS_FLOAT32: + case ANEURALNETWORKS_TENSOR_FLOAT32: + execution->sink<TensorSink<float>>(index, shape, reinterpret_cast<float *>(buffer), length); + break; + case ANEURALNETWORKS_INT32: + case ANEURALNETWORKS_TENSOR_INT32: + execution->sink<TensorSink<int32_t>>(index, shape, reinterpret_cast<int32_t *>(buffer), + length); + break; + case ANEURALNETWORKS_UINT32: + execution->sink<TensorSink<uint32_t>>(index, shape, reinterpret_cast<uint32_t *>(buffer), + length); + break; + case ANEURALNETWORKS_TENSOR_QUANT8_ASYMM: + execution->sink<TensorSink<uint8_t>>(index, shape, reinterpret_cast<uint8_t *>(buffer), + length); + break; + default: + throw std::runtime_error("Not supported, yet"); + break; + } +} + +// +// NNAPI Implementation +// +int ANeuralNetworksExecution_create(ANeuralNetworksCompilation *compilation, + ANeuralNetworksExecution **execution) +{ + if ((compilation == nullptr) || (execution == nullptr)) + { + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + std::shared_ptr<const ::internal::arm_compute::Plan> plan; + compilation->publish(plan); + ANeuralNetworksExecution *execution_ptr = new ANeuralNetworksExecution{plan}; + if (execution_ptr == nullptr) + { + return ANEURALNETWORKS_OUT_OF_MEMORY; + } + *execution = execution_ptr; + + return ANEURALNETWORKS_NO_ERROR; +} + +int ANeuralNetworksExecution_setInput(ANeuralNetworksExecution *execution, int32_t index, + const ANeuralNetworksOperandType *type, const void *buffer, + size_t length) +{ + // Don't check type + // Comment about ANeuralNetworksOperandType in NeuralNetworks.h: + // If the input or output is optional and omitted then it need not have a fully specified tensor + // operand type + if ((execution == nullptr) || ((buffer == nullptr) && (length != 0))) + { + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + const auto &operands = execution->plan().model().operands(); + + // TODO Check type conflicts + + // NOTE The current implemenation assumes that every input is a feature map. + // TODO Remove this assumption + const auto operand_index = execution->plan().model().inputs.at(index); + int32_t input_type = operands.at(operand_index).type(); + // NOTE TFLite passes type parameter unconditionally as nullptr. + // Is it necessary to reget type value already set in model step? + if (type != nullptr) + { + input_type = type->type; + } + + auto shape = operands.at(operand_index).shape(); + auto rank = shape.rank(); + + if (rank == 1) + { + const auto len = shape.dim(0); + + asVectorSource(execution, input_type, index, len, buffer, length); + } + else if (rank == 2) + { + const auto &operand_shape = shape.asMatrix(); + + asMatrixSource(execution, input_type, index, operand_shape, buffer, length); + } + else if (rank == 3) + { + const auto &operand_shape = shape.asTensor(); + + asTensor3DSource(execution, input_type, index, operand_shape, buffer, length); + } + else if (rank == 4) + { + const auto &operand_shape = shape.asFeature(); + + asFeatureSource(execution, input_type, index, operand_shape, buffer, length); + } + else + { + // NOTE TensorSource is much slower than specialized Source(s) + const auto &operand_shape = shape.asTensor(); + + asTensorSource(execution, input_type, index, operand_shape, buffer, length); + } + + return ANEURALNETWORKS_NO_ERROR; +} + +// squeeze(shape) eliminates all the dimensions whose dimensionality is 1 +// For example, squeeze([3, 1, 3]) returns [3, 3] +static nnfw::misc::tensor::Shape squeeze(const nnfw::misc::tensor::Shape &shape) +{ + nnfw::misc::tensor::Shape res(0); + + for (uint32_t axis = 0; axis < shape.rank(); ++axis) + { + if (shape.dim(axis) != 1) + { + res.append(shape.dim(axis)); + } + } + + return res; +} + +int ANeuralNetworksExecution_setOutput(ANeuralNetworksExecution *execution, int32_t index, + const ANeuralNetworksOperandType *type, void *buffer, + size_t length) +{ + // Don't check type + // Comment about ANeuralNetworksOperandType in NeuralNetworks.h: + // If the input or output is optional and omitted then it need not have a fully specified tensor + // operand type + if ((execution == nullptr) || ((buffer == nullptr) && (length != 0))) + { + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + const auto &operands = execution->plan().model().operands(); + + // TODO Check type conflicts + + const auto operand_index = execution->plan().model().outputs.at(index); + int32_t output_type = operands.at(operand_index).type(); + const auto &output_shape = operands.at(operand_index).shape(); + + if (output_shape.rank() == 1) + { + const auto len = output_shape.dim(0); + + asVectorSink(execution, output_type, index, len, buffer, length); + } + else if (output_shape.rank() == 2) + { + const auto H = output_shape.dim(0); + const auto W = output_shape.dim(1); + + asMatrixSink(execution, output_type, index, H, W, buffer, length); + } + else if (output_shape.rank() == 3) + { + asTensor3DSink(execution, output_type, index, output_shape, buffer, length); + } + else if ((output_shape.rank() == 4)) + { + const auto &operand_shape = operands.at(operand_index).shape().asFeature(); + + asFeatureSink(execution, output_type, index, operand_shape, buffer, length); + } + else + { + // NOTE TensorSink is much slower than specialized Sink(s) + const auto &shape = operands.at(operand_index).shape(); + asTensorSink(execution, output_type, index, shape, buffer, length); + } + + return ANEURALNETWORKS_NO_ERROR; +} + +int ANeuralNetworksExecution_startCompute(ANeuralNetworksExecution *execution, + ANeuralNetworksEvent **event) +{ + if ((execution == nullptr) || (event == nullptr)) + { + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + // TODO: Handle event + ANeuralNetworksEvent *event_ptr = new ANeuralNetworksEvent{}; + if (event_ptr == nullptr) + { + return ANEURALNETWORKS_OUT_OF_MEMORY; + } + *event = event_ptr; + + return ANeuralNetworksExecution_compute(execution); +} + +int ANeuralNetworksExecution_compute(ANeuralNetworksExecution *execution) +{ + if (execution == nullptr) + { + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + const bool sync = profiling::Context::get().sync(); + const auto &plan = execution->plan(); + const auto &model = plan.model(); + + // Set input(s) + for (uint32_t n = 0; n < model.inputs.size(); ++n) + { + auto setter = [&](::arm_compute::ITensor &tensor) { execution->source(n).push(tensor); }; + + // Some operand may not be defined at plan. Because some operands + // may be useless at ACL (ex. shape tensor for Reshape operator) + // So added a sanity check. + if (plan.operands().exist(model.inputs.at(n))) + { + plan.operands().at(model.inputs.at(n)).access(setter); + } + } + + const auto &operations = execution->plan().operations(); + + for (uint32_t n = 0; n < operations.size(); ++n) + { + auto prof = profiling::Context::get().getProfiler(); + SCOPED_OPERATOR_PROFILE(prof, operations.at(n).op_idx()); + operations.at(n).run(); + + if (sync) + { + arm_compute::CLScheduler::get().sync(); + } + } + + // Get output(s) + for (uint32_t n = 0; n < model.outputs.size(); ++n) + { + auto getter = [&](::arm_compute::ITensor &tensor) { execution->sink(n).pull(tensor); }; + + plan.operands().at(model.outputs.at(n)).access(getter); + } + + return ANEURALNETWORKS_NO_ERROR; +} + +void ANeuralNetworksExecution_free(ANeuralNetworksExecution *execution) {} + +// TODO: implement this. added to fix link error on test build. +int ANeuralNetworksExecution_setInputFromMemory(ANeuralNetworksExecution *execution, int32_t index, + const ANeuralNetworksOperandType *type, + const ANeuralNetworksMemory *memory, size_t offset, + size_t length) +{ + if ((execution == nullptr) || (memory == nullptr)) + { + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + assert(false); + return -1; +} + +// TODO: implement this. added to fix link error on test build. +int ANeuralNetworksExecution_setOutputFromMemory(ANeuralNetworksExecution *execution, int32_t index, + const ANeuralNetworksOperandType *type, + const ANeuralNetworksMemory *memory, size_t offset, + size_t length) +{ + if ((execution == nullptr) || (memory == nullptr)) + { + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + assert(false); + return -1; +} + +int ANeuralNetworksExecution_getOutputOperandRank(ANeuralNetworksExecution *execution, + int32_t index, uint32_t *rank) +{ + if ((execution == nullptr) || (rank == nullptr)) + { + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + const auto &operands = execution->plan().model().operands(); + const auto operand_index = execution->plan().model().outputs.at(index); + const auto &output_shape = operands.at(operand_index).shape(); + + *rank = output_shape.rank(); + + return ANEURALNETWORKS_NO_ERROR; +} + +int ANeuralNetworksExecution_getOutputOperandDimensions(ANeuralNetworksExecution *execution, + int32_t index, uint32_t *dimensions) +{ + if ((execution == nullptr) || (dimensions == nullptr)) + { + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + const auto &operands = execution->plan().model().operands(); + const auto operand_index = execution->plan().model().outputs.at(index); + const auto &output_shape = operands.at(operand_index).shape(); + + for (uint32_t axis = 0; axis < output_shape.rank(); ++axis) + { + dimensions[axis] = static_cast<uint32_t>(output_shape.dim(axis)); + } + + return ANEURALNETWORKS_NO_ERROR; +} diff --git a/runtime/contrib/pure_arm_compute/src/execution.h b/runtime/contrib/pure_arm_compute/src/execution.h new file mode 100644 index 000000000..f55ab3fbf --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/execution.h @@ -0,0 +1,119 @@ +/* + * 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. + */ + +/** + * @file execution.h + * @brief This file contains ANeuralNetworksExecution class for handling Execution NNAPI such as + * ANeuralNetworksExecution_create, ANeuralNetworksExecution_setInput + * @ingroup COM_AI_RUNTIME + */ + +#ifndef __EXECUTION_H__ +#define __EXECUTION_H__ + +#include "internal/arm_compute.h" +#include "internal/Sink.h" +#include "internal/Source.h" + +/** + * @brief struct to express Execution of NNAPI + */ +struct ANeuralNetworksExecution +{ +public: + /** + * @brief Construct with params + * @param [in] plan Pointer to get internal::arm_compute::Plan + */ + ANeuralNetworksExecution(const std::shared_ptr<const internal::arm_compute::Plan> &plan) + : _plan{plan} + { + _sources.resize(_plan->model().inputs.size()); + _sinks.resize(_plan->model().outputs.size()); + } + +public: + /** + * @brief Get reference of internal::arm_compute::Plan + * @return Const reference of internal::arm_compute::Plan + */ + const internal::arm_compute::Plan &plan(void) const { return *_plan; } + +private: + std::shared_ptr<const internal::arm_compute::Plan> _plan; + +public: + /** + * @brief Set the nth source with param + * @param [in] n Index of the nth source + * @param [in] source Pointer to set the nth source from + * @return N/A + */ + // TODO Use InputIndex instead of int + void source(int n, std::unique_ptr<Source> &&source) { _sources.at(n) = std::move(source); } + /** + * @brief Set the nth source with param + * @param [in] n Index of the nth source + * @param [in] args Arguments to set the nth source from + * @return N/A + */ + template <typename T, typename... Args> void source(int n, Args &&... args) + { + source(n, std::unique_ptr<T>{new T{std::forward<Args>(args)...}}); + } + +public: + /** + * @brief Get the nth source + * @param [in] n Index of the nth source + * @return Const reference of Source + */ + const Source &source(int n) const { return *(_sources.at(n)); } + +public: + /** + * @brief Set the nth sink with param + * @param [in] n Index of the nth sink + * @param [in] sink Pointer to set the nth sink from + * @return N/A + */ + // TODO Use OutputIndex instead of int + void sink(int n, std::unique_ptr<Sink> &&sink) { _sinks.at(n) = std::move(sink); } + /** + * @brief Set the nth sink with param + * @param [in] n Index of the nth sink + * @param [in] args Arguments to set the nth sink from + * @return N/A + */ + template <typename T, typename... Args> void sink(int n, Args &&... args) + { + sink(n, std::unique_ptr<T>{new T{std::forward<Args>(args)...}}); + } + +public: + /** + * @brief Get the nth sink + * @param [in] n Index of the nth sink + * @return Const reference of Sink + */ + const Sink &sink(int n) const { return *(_sinks.at(n)); } + +private: + std::vector<std::unique_ptr<Source>> _sources; + std::vector<std::unique_ptr<Sink>> _sinks; +}; + +#endif diff --git a/runtime/contrib/pure_arm_compute/src/internal/FeatureSink.h b/runtime/contrib/pure_arm_compute/src/internal/FeatureSink.h new file mode 100644 index 000000000..7c6884141 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/FeatureSink.h @@ -0,0 +1,80 @@ +/* + * 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. + */ + +/** + * @file       FeatureSink.h + * @brief      This file contains FeatureSink class + * @ingroup    COM_AI_RUNTIME + */ + +#ifndef __INTERNAL_FEATURE_SINK_H__ +#define __INTERNAL_FEATURE_SINK_H__ + +#include "internal/Sink.h" +#include "internal/nnapi/feature/View.h" +#include "internal/arm_compute/feature/View.h" + +#include <misc/feature/Shape.h> +#include "misc/feature/IndexIterator.h" + +/** + * @brief Class to store Feature(4D) output data. + * This is for pulling data to internal tensor from other tensor. + * @tparam T Type of the data elements + */ +template <typename T> class FeatureSink final : public Sink +{ +public: + /** + * @brief Construct a FeatureSink object + * + * @param[in] shape 4D tensor dimensions for this feature + * @param[in] base Base pointer of the actual data + * @param[in] size Size of the data + */ + FeatureSink(const nnfw::misc::feature::Shape &shape, T *base, const size_t size) + : _shape{shape}, _base{base}, _size{size} + { + // DO NOTHING + } + +public: + /** + * @brief Pull the data into the internal structure + * @param[in] tensor The tensor which contains source data + * @return N/A + */ + void pull(::arm_compute::ITensor &tensor) const override + { + const ::internal::arm_compute::feature::View<T> from{&tensor}; + // TODO Should remove casting. + // Inevitably casting must be done. + ::internal::nnapi::feature::View<T> into{_shape, _base, _size}; + + ::nnfw::misc::feature::iterate(_shape) + << [&](uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) { + const auto value = from.at(batch, ch, row, col); + into.at(batch, ch, row, col) = value; + }; + } + +private: + const nnfw::misc::feature::Shape _shape; + T *const _base; + const size_t _size; +}; + +#endif // __INTERNAL_FEATURE_SINK_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/FeatureSource.h b/runtime/contrib/pure_arm_compute/src/internal/FeatureSource.h new file mode 100644 index 000000000..772beb701 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/FeatureSource.h @@ -0,0 +1,77 @@ +/* + * 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. + */ + +/** + * @file       FeatureSource.h + * @brief      This file contains FeatureSource class + * @ingroup    COM_AI_RUNTIME + */ + +#ifndef __INTERNAL_FEATURE_SOURCE_H__ +#define __INTERNAL_FEATURE_SOURCE_H__ + +#include <misc/feature/Shape.h> +#include <misc/feature/IndexIterator.h> + +#include "internal/nnapi/feature/Reader.h" +#include "internal/arm_compute/feature/View.h" + +/** + * @brief Class to store feature(4D) input data. + * This is for push out the data to another tensor. + * @tparam T Type of the data elements + */ +template <typename T> class FeatureSource final : public Source +{ +public: + /** + * @brief Construct a FeatureSource object + * + * @param[in] shape 4D tensor dimensions for this feature + * @param[in] base Base pointer of the actual data + * @param[in] size Size of the data + */ + FeatureSource(const nnfw::misc::feature::Shape &shape, const T *base, const size_t size) + : _shape{shape}, _base{base}, _size{size} + { + // DO NOTHING + } + +public: + /** + * @brief Push the data out to the another tensor + * @param[out] The tensor that output data will be stored + * @return N/A + */ + void push(::arm_compute::ITensor &tensor) const override + { + const ::internal::nnapi::feature::Reader<T> from{_shape, _base, _size}; + ::internal::arm_compute::feature::View<T> into{&tensor}; + + ::nnfw::misc::feature::iterate(_shape) + << [&](uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) { + const auto value = from.at(batch, ch, row, col); + into.at(batch, ch, row, col) = value; + }; + } + +private: + const nnfw::misc::feature::Shape _shape; + const T *const _base; + const size_t _size; +}; + +#endif // __INTERNAL_FEATURE_SOURCE_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/IExecutionBuilder.h b/runtime/contrib/pure_arm_compute/src/internal/IExecutionBuilder.h new file mode 100644 index 000000000..2a6e2a743 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/IExecutionBuilder.h @@ -0,0 +1,49 @@ +/* + * 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. + */ + +/** + * @file IExecutionBuilder.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines interface of ExecutionBuilder + */ +#ifndef __INTERNAL_IEXECUTION_BUILDER_H__ +#define __INTERNAL_IEXECUTION_BUILDER_H__ + +#include <arm_compute/runtime/IFunction.h> + +#include <memory> +#include <string> + +/** + * @brief Struct to define interface of ExecutionBuilder + */ +struct IExecutionBuilder +{ + /** + * @brief Destroy the IExecutionBuilder object + */ + virtual ~IExecutionBuilder() = default; + + /** + * @brief Append function to execute + * @param[in] name Name of function + * @param[in] f Function to append + * @return N/A + */ + virtual void append(const std::string &name, std::unique_ptr<::arm_compute::IFunction> &&f) = 0; +}; + +#endif // __INTERNAL_IEXECUTION_BUILDER_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/MatrixSink.h b/runtime/contrib/pure_arm_compute/src/internal/MatrixSink.h new file mode 100644 index 000000000..23ecc112b --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/MatrixSink.h @@ -0,0 +1,91 @@ +/* + * 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. + */ + +/** + * @file MatrixSink.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines MatrixSink class + */ +#ifndef __INTERNAL_MATRIX_SINK_H__ +#define __INTERNAL_MATRIX_SINK_H__ + +#include "internal/Sink.h" + +#include <arm_compute/core/ITensor.h> +#include <arm_compute/core/Window.h> +#include <arm_compute/core/Helpers.h> + +#include <cstdint> +#include <cstring> +#include <cassert> + +/** + * @brief Class to get matrix data from arm compute tensor + */ +template <typename T> class MatrixSink final : public Sink +{ +public: + /** + * @brief Construct a new Matrix Sink object + * @param[in] H Height of matrix + * @param[in] W Width of matrix + * @param[in] base Pointer to get data + * @param[in] size Size of matrix + */ + MatrixSink(const int32_t H, const int32_t W, T *base, const size_t size) + : _height{H}, _width{W}, _base{base} + { + assert(size >= _height * _width * sizeof(T)); + } + +public: + /** + * @brief Get matrix data from arm compute tensor to base + * @param[in] tensor Tensor object of arm compute to get data + * @return N/A + */ + void pull(::arm_compute::ITensor &tensor) const override + { + assert(tensor.info()->dimension(0) == _width); + assert(tensor.info()->dimension(1) == _height); + + using ::arm_compute::Window; + using ::arm_compute::Iterator; + using ::arm_compute::Coordinates; + using ::arm_compute::execute_window_loop; + + Window window; + + window.use_tensor_dimensions(tensor.info()->tensor_shape(), ::arm_compute::Window::DimY); + + Iterator it(&tensor, window); + execute_window_loop(window, + [&](const ::arm_compute::Coordinates &id) { + const auto row = id.y(); + memcpy(_base + row * _width, it.ptr(), _width * sizeof(T)); + }, + it); + } + +private: + const int32_t _height; + const int32_t _width; + +private: + T *const _base; +}; + +#endif // __INTERNAL_MATRIX_SINK_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/MatrixSource.h b/runtime/contrib/pure_arm_compute/src/internal/MatrixSource.h new file mode 100644 index 000000000..71d6a804f --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/MatrixSource.h @@ -0,0 +1,82 @@ +/* + * 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. + */ + +/** + * @file MatrixSource.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines MatrixSource class + */ +#ifndef __INTERNAL_MATRIX_SOURCE_H__ +#define __INTERNAL_MATRIX_SOURCE_H__ + +#include <arm_compute/core/ITensor.h> +#include <arm_compute/core/Window.h> +#include <arm_compute/core/Helpers.h> + +#include "internal/Source.h" + +/** + * @brief Class to push matrix data to arm compute tensor + */ +template <typename T> class MatrixSource final : public Source +{ +public: + /** + * @brief Construct a new MatrixSource object + * @param[in] shape Shape of matrix + * @param[in] base Pointer of matrix data to push + * @param[in] size Size of matrix + */ + MatrixSource(const nnfw::misc::matrix::Shape &shape, const T *base, const size_t size) + : _shape{shape}, _base{base}, _size{size} + { + // do nothing + } + +public: + /** + * @brief Push matrix data to arm compute tensor + * @param[out] tensor Tensor object of arm compute to push matrix data + * @return N/A + */ + void push(::arm_compute::ITensor &tensor) const override + { + using ::arm_compute::Window; + using ::arm_compute::Iterator; + using ::arm_compute::Coordinates; + using ::arm_compute::execute_window_loop; + + Window window; + window.use_tensor_dimensions(tensor.info()->tensor_shape(), ::arm_compute::Window::DimY); + + int32_t width = _shape.W; + + Iterator it(&tensor, window); + execute_window_loop(window, + [&](const ::arm_compute::Coordinates &id) { + const auto height = id.y(); + memcpy(it.ptr(), _base + height * width, width * sizeof(T)); + }, + it); + } + +private: + const nnfw::misc::matrix::Shape _shape; + const T *const _base; + const size_t _size; +}; + +#endif // __INTERNAL_MATRIX_SOURCE_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/Model.cc b/runtime/contrib/pure_arm_compute/src/internal/Model.cc new file mode 100644 index 000000000..03753fea2 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/Model.cc @@ -0,0 +1,128 @@ +/* + * 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 "internal/Model.h" + +namespace internal +{ +namespace tflite +{ +namespace operand +{ + +Shape::Shape(uint32_t rank) : nnfw::misc::tensor::Shape(rank) +{ + // DO NOTHING +} + +int32_t Shape::asVector(void) const +{ + assert(rank() == 1); + + return dim(0); +} + +nnfw::misc::matrix::Shape Shape::asMatrix(void) const +{ + assert(rank() == 2); + + const auto height = dim(0); + const auto width = dim(1); + + return nnfw::misc::matrix::Shape(height, width); +} + +nnfw::misc::feature::Shape Shape::asFeature(void) const +{ + assert(rank() == 4); + + // Feature Map in NNAPI + // - Dimension(0) -> Batch + // - Dimension(1) -> Height + // - Dimension(2) -> Width + // - Dimension(3) -> Depth + + const auto batch = dim(0); + const auto depth = dim(3); + const auto height = dim(1); + const auto width = dim(2); + + return nnfw::misc::feature::Shape(batch, depth, height, width); +} + +nnfw::misc::tensor::Shape Shape::asTensor(void) const +{ + return nnfw::misc::tensor::Shape(*this); // this shape represents shape of NNAPI +} + +nnfw::misc::kernel::Shape Shape::asKernel(void) const +{ + assert(rank() == 4); + + // Convolution Kernel in NNAPI + // - Dimension(0) -> Count + // - Dimension(1) -> Height + // - Dimension(2) -> Width + // - Dimension(3) -> Depth + const auto count = dim(0); + const auto depth = dim(3); + const auto height = dim(1); + const auto width = dim(2); + + return nnfw::misc::kernel::Shape(count, depth, height, width); +} + +// Extended dimension is filled with 1. +void Shape::extendRank(size_t to_rank) +{ + for (int i = rank() + 1; i <= to_rank; ++i) + { + prepend(1); + } +} + +} // namespace operand +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace operand +{ + +Index Set::append(const Shape &shape, int32_t type, float scale, int32_t zeroPoint) +{ + int32_t index = _objects.size(); + + _objects.emplace_back(new Object{shape, type, scale, zeroPoint}); + + return Index{index}; +} + +const Object &Set::at(const Index &index) const { return *(_objects.at(index.asInt())); } + +Object &Set::at(const Index &index) { return *(_objects.at(index.asInt())); } + +bool Set::exist(const Index &index) const +{ + return index.asInt() >= 0 && index.asInt() < _objects.size(); +} + +} // namespace operand +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/Model.h b/runtime/contrib/pure_arm_compute/src/internal/Model.h new file mode 100644 index 000000000..bdcf32f6f --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/Model.h @@ -0,0 +1,538 @@ +/* + * 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. + */ + +/** + * @file Model.h + * @brief This file contains classes for handle internal Model object + * @ingroup COM_AI_RUNTIME + */ + +#ifndef __INTERNAL_MODEL_H__ +#define __INTERNAL_MODEL_H__ + +namespace internal +{ +namespace tflite +{ +namespace operand +{ + +/** + * @brief Class to express index of operand. + */ +class Index +{ +public: + /** + * @brief Construct a new Index object for operand with param. + * @param [in] value The number of index + */ + explicit Index(int value) : _value{value} + { + // DO NOTHING + } + +public: + /** + * @brief Get index value as int + * @return Index value as int + */ + int asInt(void) const { return _value; } + +private: + int _value; +}; + +} // namespace operand +} // namespace tflite +} // namespace internal + +#include <vector> +#include <cstdint> + +#include "misc/feature/Shape.h" +#include "misc/matrix/Shape.h" +#include "misc/kernel/Shape.h" +#include "misc/tensor/Shape.h" + +namespace internal +{ +namespace tflite +{ +namespace operand +{ + +/** + * @brief Class to express shape of operand. + */ +struct Shape : public nnfw::misc::tensor::Shape +{ +public: + /** + * @brief Construct a new Shape object for operand with param. + * @param [in] rank The rank value of shape + */ + Shape(uint32_t rank); + +public: + /** + * @brief Get dimension value of tensor as vector + * @return Dimension value(int32_t) of tensor as vector + */ + int32_t asVector(void) const; + /** + * @brief Get dimension values of tensor as feature::Shape + * @return Dimension values of tensor as feature::Shape + */ + nnfw::misc::feature::Shape asFeature(void) const; + /** + * @brief Get dimension values of tensor as matrix::Shape + * @return Dimension values of tensor as matrix::Shape + */ + nnfw::misc::matrix::Shape asMatrix(void) const; + /** + * @brief Get dimension values of tensor as kernel::Shape + * @return Dimension values of tensor as kernel::Shape + */ + nnfw::misc::kernel::Shape asKernel(void) const; + /** + * @brief Get dimension values of tensor::Shape + * @return Dimension values of tensor::Shape + */ + nnfw::misc::tensor::Shape asTensor(void) const; + +public: + /** + * @brief Extend rank of Shape object for operand with param. + * @param [in] to_rank The rank value to be extended to + * @return N/A + */ + void extendRank(size_t); +}; + +} // namespace operand +} // namespace tflite +} // namespace internal + +#include <algorithm> + +namespace internal +{ +namespace tflite +{ +namespace operand +{ + +/** + * @brief Class to have data of operand. + */ +struct Data +{ + /** + * @brief Destruct this object + */ + virtual ~Data() = default; + + /** + * @brief Get size of data + * @return size of data + */ + virtual size_t size(void) const = 0; + /** + * @brief Get the base address of data + * @return the base address of data + */ + virtual const uint8_t *base(void) const = 0; +}; + +/** + * @brief Class to have cached data of operand. + */ +class CachedData final : public Data +{ +public: + /** + * @brief Construct a new CachedData object for operand with param. + * @param [in] base the base address of data + * @param [in] size the size of data + */ + CachedData(const uint8_t *base, size_t size) : _base{new uint8_t[size]}, _size{size} + { + std::copy(base, base + size, _base); + } + +public: + /** + * @brief Destruct this object + */ + ~CachedData() { delete[] _base; } + +public: + /** + * @brief Get size of data + * @return size of data + */ + size_t size(void) const override { return _size; } + /** + * @brief Get the base address of data + * @return the base address of data + */ + const uint8_t *base(void) const override { return _base; } + +private: + uint8_t *_base; + size_t _size; +}; + +/** + * @brief Class to have external data of operand. + */ +class ExternalData final : public Data +{ +public: + /** + * @brief Construct a new ExternalData object for operand with param. + * @param [in] base the base address of data + * @param [in] size the size of data + */ + ExternalData(const uint8_t *base, size_t size) : _base{base}, _size{size} + { + // DO NOTHING + } + +public: + /** + * @brief Get size of data + * @return size of data + */ + size_t size(void) const override { return _size; } + /** + * @brief Get the base address of data + * @return the base address of data + */ + const uint8_t *base(void) const override { return _base; } + +private: + const uint8_t *_base; + const size_t _size; +}; + +} // namespace operand +} // namespace tflite +} // namespace internal + +#include <memory> +#include <cassert> +#include <functional> +#include "internal/Swizzle.h" + +namespace internal +{ +namespace tflite +{ +namespace operand +{ + +/** + * @brief Class to express operand as object. + */ +class Object +{ +public: + /** + * @brief Construct a new Object object for operand with param. + * @param [in] shape shape of operand + * @param [in] type type of operand + * @param [in] scale scale of operand + * @param [in] zeroPoint zeroPoint of operand + */ + explicit Object(const Shape &shape, const int32_t type, const float scale, + const int32_t zeroPoint) + : _shape{shape}, _type{type}, _scale{scale}, _zeroPoint{zeroPoint} + { + // DO NOTHING + } + +public: + /** + * @brief Get shape of operand + * @return Reference of shape of operand + */ + const Shape &shape(void) const { return _shape; } + /** + * @brief Get type of operand + * @return type of operand + */ + const int32_t type(void) const { return _type; } + /** + * @brief Get scale of operand + * @return scale of operand + */ + const float scale(void) const { return _scale; } + /** + * @brief Get zeroPoint of operand + * @return zeroPoint of operand + */ + const int32_t zeroPoint(void) const { return _zeroPoint; } + +private: + void data(std::unique_ptr<Data> &&data) { _data = std::move(data); } + +public: + /** + * @brief Get data of operand + * @return Reference of data of operand + */ + const Data &data(void) const { return *_data; } + /** + * @brief Get true if Object has data, otherwise @c false + * @return @c true if Object has data, otherwise @c false + */ + bool hasData(void) const { return _data != nullptr; } + +public: + /** + * @brief Set data of operand with param + * @param [in] args arguments of data to be set + * @return N/A + */ + template <typename T, typename... Args> void data(Args &&... args) + { + data(std::unique_ptr<T>(new T{std::forward<Args>(args)...})); + } + +public: + /** + * @brief Get value of data as scalar + * @return value of data as scalar + */ + template <typename T> T asScalar(void) const + { + assert((_shape.rank() == 0) || ((_shape.rank() == 1) && (_shape.dim(0) == 1))); + assert(_data != nullptr); + assert((_data->base() != nullptr) && (_data->size() == sizeof(T))); + + return *(reinterpret_cast<const T *>(_data->base())); + } + +public: + /** + * @brief Get value of data as ReorderBits + * @param [in] numOfBits The number of bits to be reordered to + * @return value of data as ReorderBits + */ + template <typename T> T asReorderBits(size_t numOfBits) const + { + assert((_shape.rank() == 0) || ((_shape.rank() == 1) && (_shape.dim(0) == 1))); + assert(_data != nullptr); + assert((_data->base() != nullptr) && (_data->size() == sizeof(T))); + + return ReorderBits<T>(asScalar<T>(), numOfBits); + } + +private: + const Shape _shape; + const int32_t _type; + const float _scale; + const int32_t _zeroPoint; + std::unique_ptr<Data> _data; +}; + +} // namespace operand +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace operand +{ + +/** + * @brief Class to have object instances in a kind of set + */ +class Set +{ +public: + /** + * @brief Iterate objects with fn + * @param [in] fn function to be iterated + * @return N/A + */ + void iterate(const std::function<void(const Index &)> &fn) + { + for (uint32_t n = 0; n < _objects.size(); ++n) + { + const Index operand_index{static_cast<int>(n)}; + fn(operand_index); + } + } + +public: + /** + * @brief Append Object for operand with param + * @param [in] shape shape of operand + * @param [in] type type of operand + * @param [in] scale scale of operand + * @param [in] zeroPoint zeroPoint of operand + * @return Value of Index which has been appended to + */ + Index append(const Shape &, int32_t type, float scale, int32_t zeroPoint); + +public: + /** + * @brief Get Object at Index + * @param [in] index Index to be at + * @return Const refernece of Object + */ + const Object &at(const Index &) const; + /** + * @brief Get Object at Index + * @param [in] index Index to be at + * @return Refernece of Object + */ + Object &at(const Index &); + /** + * @brief Get size of operands in Set + * @return Value of size + */ + size_t size(void) const { return _objects.size(); } + bool exist(const Index &) const; + +private: + std::vector<std::unique_ptr<Object>> _objects; +}; + +} // namespace operand +} // namespace tflite +} // namespace internal + +#include "internal/op/NodeVisitor.h" + +namespace internal +{ +namespace tflite +{ +namespace op +{ + +/** + * @brief Class to have sequence operators. + */ +class Sequence +{ +public: + /** + * @brief Construct a new Sequence object for operator as default + */ + Sequence() = default; + +public: + /** + * @brief Get size of operators in Sequence + * @return Value of size + */ + uint32_t size(void) const { return _ops.size(); } + +public: + /** + * @brief Get op::Node at Index + * @param [in] nth index to be at + * @return Refernece of op::Node + */ + op::Node &at(uint32_t nth) { return *(_ops.at(nth)); } + /** + * @brief Get op::Node at Index + * @param [in] nth index to be at + * @return Const refernece of op::Node + */ + const op::Node &at(uint32_t nth) const { return *(_ops.at(nth)); } + +private: + Sequence &emplace_back(std::unique_ptr<op::Node> &&node) + { + _ops.emplace_back(std::move(node)); + return (*this); + } + +public: + /** + * @brief Add op::Node with param + * @param [in] args arguments of op::Node to be set + * @return Reference of Sequence + */ + template <typename T, typename... Args> Sequence &emplace_back(Args &&... args) + { + return emplace_back(std::unique_ptr<T>(new T{std::forward<Args>(args)...})); + } + +private: + std::vector<std::unique_ptr<op::Node>> _ops; +}; + +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ + +/** + * @brief Class to have operand::Set as operands and op::Sequence as operators + */ +class Model +{ +public: + /** + * @brief Get operand::Set + * @return Reference of operand::Set + */ + operand::Set &operands(void) { return _operands; } + /** + * @brief Get operand::Set + * @return Const reference of operand::Set + */ + const operand::Set &operands(void) const { return _operands; } + +public: + /** + * @brief Get op::Sequence + * @return Reference of op::Sequence + */ + op::Sequence &operations(void) { return _operations; } + /** + * @brief Get op::Sequence + * @return Const reference of op::Sequence + */ + const op::Sequence &operations(void) const { return _operations; } + +private: + operand::Set _operands; + op::Sequence _operations; + +public: + // TODO Hide these fields + std::vector<operand::Index> inputs; /**< indexes of operand as input */ + std::vector<operand::Index> outputs; /**< indexes of operand as output */ +}; + +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_MODEL_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/Sink.h b/runtime/contrib/pure_arm_compute/src/internal/Sink.h new file mode 100644 index 000000000..6f44561ea --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/Sink.h @@ -0,0 +1,45 @@ +/* + * 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. + */ + +/** + * @file Sink.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines Sink struct + */ +#ifndef __INTERNAL_SINK_H__ +#define __INTERNAL_SINK_H__ + +#include <arm_compute/core/ITensor.h> + +/** + * @brief Struct to get tensor data from arm compute tensor (abstract) + */ +struct Sink +{ + /** + * @brief Destroy the Sink object + */ + virtual ~Sink() = default; + + /** + * @brief Get tensor data from arm compute tensor + * @param[in] tensor Tensor object of arm compute to get data + * @return N/A + */ + virtual void pull(::arm_compute::ITensor &tensor) const = 0; +}; + +#endif // __INTERNAL_SINK_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/Sinks.h b/runtime/contrib/pure_arm_compute/src/internal/Sinks.h new file mode 100644 index 000000000..7317c67c1 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/Sinks.h @@ -0,0 +1,97 @@ +/* + * 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. + */ + +/** + * @file       Sinks.h + * @brief      This file contains TensorSink class + * @ingroup    COM_AI_RUNTIME + */ + +#ifndef __INTERNAL_SINKS_H__ +#define __INTERNAL_SINKS_H__ + +#include "internal/Sink.h" + +// TODO Extract TensorSink into TensorSink.h +// +// TensorSink +// +#include "internal/Swizzle.h" + +#include "internal/nnapi/tensor/View.h" +#include "internal/arm_compute/tensor/View.h" + +#include "misc/tensor/IndexIterator.h" + +/** + * @brief Class to store NN model output data for general-shaped tensors. + * This is for pulling data to internal tensor from other tensor. + * @tparam T Type of the data elements + */ +template <typename T> class TensorSink final : public Sink +{ +public: + /** + * @brief Construct a TensorSink object + * + * @param[in] shape general-shaped tensor dimensions + * @param[in] base Base pointer of the actual data + * @param[in] size Size of the data + */ + TensorSink(const nnfw::misc::tensor::Shape &shape, T *base, const size_t size) + : _shape{shape}, _base{base}, _size{size} + { + // DO NOTHING + } + +public: + /** + * @brief Pull the data into the internal structure + * @param[in] tensor The tensor which contains source data + * @return N/A + */ + void pull(::arm_compute::ITensor &tensor) const override + { + const ::internal::arm_compute::tensor::View<T> from{&tensor}; + ::internal::nnapi::tensor::View<T> into{_shape, _base, _size}; + + using ::nnfw::misc::tensor::iterate; + using ::nnfw::misc::tensor::Index; + + const uint32_t rank = _shape.rank(); + + ::nnfw::misc::tensor::iterate(_shape) << [&](const Index &raw) { + Index permuted(raw.rank()); + + for (uint32_t axis = 0; axis < rank; ++axis) + { + permuted.at(ToARMComputeAxis(rank, axis).value()) = raw.at(axis); + } + + const auto value = from.at(permuted); + into.at(raw) = value; + }; + } + +private: + const nnfw::misc::tensor::Shape _shape; + +private: + T *const _base; + const size_t _size; +}; + +#endif // __INTERNAL_SINKS_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/Source.h b/runtime/contrib/pure_arm_compute/src/internal/Source.h new file mode 100644 index 000000000..fa8f1e811 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/Source.h @@ -0,0 +1,46 @@ +/* + * 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. + */ + +/** + * @file Source.h + * @brief This file contains Source struct for pushing ITensor + * @ingroup COM_AI_RUNTIME + */ + +#ifndef __INTERNAL_SOURCE_H__ +#define __INTERNAL_SOURCE_H__ + +#include <arm_compute/core/ITensor.h> + +/** + * @brief Struct to push inner source to ITensor. + */ +struct Source +{ + /** + * @brief Destructor as default + */ + virtual ~Source() = default; + + /** + * @brief Push inner source to ITensor + * @param [in] tensor ITensor to be pushed into + * @return N/A + */ + virtual void push(::arm_compute::ITensor &tensor) const = 0; +}; + +#endif // __INTERNAL_SOURCE_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/Swizzle.h b/runtime/contrib/pure_arm_compute/src/internal/Swizzle.h new file mode 100644 index 000000000..f127b8a3b --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/Swizzle.h @@ -0,0 +1,115 @@ +/* + * 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. + */ + +/** + * @file Swizzle.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines ARMComputeAxis class and utility functions to support mapping + * between arm compute axis and NNAPI axis + */ +#ifndef __SWIZZLE_H__ +#define __SWIZZLE_H__ + +/** + * @brief Class to represent arm compute axis + */ +class ARMComputeAxis +{ +public: + /** + * @brief Construct a new ARMComputeAxis object + */ + ARMComputeAxis() = default; + +public: + /** + * @brief Construct a new ARMComputeAxis object + * @param[in] value Raw axis number + */ + explicit ARMComputeAxis(uint32_t value) : _value{value} + { + // DO NOTHING + } + +public: + /** + * @brief Get raw axis number + * @return Raw axis number + */ + uint32_t value(void) const { return _value; } + +private: + uint32_t _value; +}; + +/** + * @brief Convert T/F Lite / NNAPI axis (based on ...NHWC) to arm compute axis (WHCN...) + * @param[in] rank Rank of shape + * @param[in] axis Axis to map + * @return ARMComputeAxis including arm compute axis info + */ +inline ARMComputeAxis ToARMComputeAxis(uint32_t rank, uint32_t axis) +{ + assert(rank > axis); + const ARMComputeAxis reversed{(rank - axis) - 1}; + + if (rank < 4) + { + return reversed; + } + + // DEPTH + if (0 == reversed.value()) + { + return ARMComputeAxis{2}; + } + // WIDTH + if (1 == reversed.value()) + { + return ARMComputeAxis{0}; + } + // HEIGHT + if (2 == reversed.value()) + { + return ARMComputeAxis{1}; + } + + // ELSE + return reversed; +} + +#include <cassert> + +/** + * @brief Covert bitmask info from NNAPI axis to arm compute axis + * @param[in] in Bitmask data + * @param[in] numOfBits Used bits (rank) + * @return Coverted bitmask + */ +template <typename T> inline T ReorderBits(T in, size_t numOfBits) +{ + assert(numOfBits > 0); + T out = 0; + for (int32_t i = numOfBits - 1; i >= 0; --i) + { + const uint32_t toShift = numOfBits - ToARMComputeAxis(numOfBits, i).value() - 1; + out += ((in & 1) << toShift); + in >>= 1; + } + return out; +} + +#endif // __SWIZZLE_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/Tensor3DSink.h b/runtime/contrib/pure_arm_compute/src/internal/Tensor3DSink.h new file mode 100644 index 000000000..1e14e2d6c --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/Tensor3DSink.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. + */ + +/** + * @file Tensor3DSink.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines Tensor3DSink class + */ +#ifndef __TENSOR3D_SINK_H__ +#define __TENSOR3D_SINK_H__ + +#include "internal/Sink.h" + +// +// This is mempcy() version of generic TensorSink for 3D tensor +// +#include <arm_compute/core/ITensor.h> +#include <arm_compute/core/Window.h> +#include <arm_compute/core/Helpers.h> + +/** + * @brief Class to get tensor data from arm compute tensor + */ +template <typename T> class Tensor3DSink final : public Sink +{ +public: + /** + * @brief Construct a new Tensor3DSink object + * @param[in] shape Shape of tensor + * @param[in] base Pointer to get data + * @param[in] size Size of tensor + */ + Tensor3DSink(const nnfw::misc::tensor::Shape &shape, T *base, const size_t size) + : _shape{shape}, _base{base}, _size{size} + { + // DO NOTHING + } + +public: + /** + * @brief Get tensor data from arm compute tensor to base + * @param[in] tensor Tensor object of arm compute to get data + * @return N/A + */ + void pull(::arm_compute::ITensor &tensor) const override + { + using ::arm_compute::Window; + using ::arm_compute::Iterator; + using ::arm_compute::Coordinates; + using ::arm_compute::execute_window_loop; + + Window window; + + window.use_tensor_dimensions(tensor.info()->tensor_shape(), ::arm_compute::Window::DimY); + int32_t height_width = _shape.dim(1) * _shape.dim(2); + int32_t width = _shape.dim(2); + + Iterator it(&tensor, window); + execute_window_loop(window, + [&](const ::arm_compute::Coordinates &id) { + const auto z = id.z(); + const auto y = id.y(); + memcpy(_base + z * height_width + y * width, it.ptr(), width * sizeof(T)); + }, + it); + } + +private: + const nnfw::misc::tensor::Shape _shape; + +private: + T *const _base; + const size_t _size; +}; + +#endif // __TENSOR3D_SINK_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/Tensor3DSource.h b/runtime/contrib/pure_arm_compute/src/internal/Tensor3DSource.h new file mode 100644 index 000000000..3d8d1b958 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/Tensor3DSource.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. + */ + +/** + * @file Tensor3DSource.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines Tensor3DSource class + */ +#ifndef __TENSOR3D_SOURCE_H__ +#define __TENSOR3D_SOURCE_H__ + +#include "internal/Source.h" + +// +// This is memcpy() version of generic TensorSource for 3D tensor +// +#include <arm_compute/core/ITensor.h> +#include <arm_compute/core/Window.h> +#include <arm_compute/core/Helpers.h> + +/** + * @brief Class to push tensor data to arm compute tensor + */ +template <typename T> class Tensor3DSource final : public Source +{ +public: + /** + * @brief Construct a new Tensor3DSource object + * @param[in] shape Shape of tensor + * @param[in] base Pointer of tensor data to push + * @param[in] size Size of tensor + */ + Tensor3DSource(const nnfw::misc::tensor::Shape &shape, const T *base, const size_t size) + : _shape{shape}, _base{base}, _size{size} + { + // DO NOTHING + } + +public: + /** + * @brief Push tensor data to arm compute tensor + * @param[out] tensor Tensor object of arm compute to push tensor data + * @return N/A + */ + void push(::arm_compute::ITensor &tensor) const override + { + using ::arm_compute::Window; + using ::arm_compute::Iterator; + using ::arm_compute::Coordinates; + using ::arm_compute::execute_window_loop; + + Window window; + + window.use_tensor_dimensions(tensor.info()->tensor_shape(), ::arm_compute::Window::DimY); + int32_t height_width = _shape.dim(1) * _shape.dim(2); + int32_t width = _shape.dim(2); + + Iterator it(&tensor, window); + execute_window_loop(window, + [&](const ::arm_compute::Coordinates &id) { + const auto z = id.z(); + const auto y = id.y(); + memcpy(it.ptr(), _base + z * height_width + y * width, width * sizeof(T)); + }, + it); + } + +private: + const nnfw::misc::tensor::Shape _shape; + +private: + const T *const _base; + const size_t _size; +}; + +#endif // __TENSOR3D_SOURCE_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/TensorSource.h b/runtime/contrib/pure_arm_compute/src/internal/TensorSource.h new file mode 100644 index 000000000..114d3588e --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/TensorSource.h @@ -0,0 +1,83 @@ +/* + * 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. + */ + +/** + * @file TensorSource.h + * @brief This file contains TensorSource class which is inherited from Source class + * @ingroup COM_AI_RUNTIME + */ + +#ifndef __INTERNAL_TENSOR_SOURCE_H__ +#define __INTERNAL_TENSOR_SOURCE_H__ + +#include <misc/tensor/Shape.h> +#include <misc/tensor/IndexIterator.h> + +#include "internal/Source.h" +#include "internal/Swizzle.h" +#include "internal/nnapi/tensor/Reader.h" +#include "internal/arm_compute/tensor/View.h" + +// NOTE TensorSource is much slower than specialized Source(s) +/** + * @brief Class to define constructor and push function + */ +template <typename T> class TensorSource final : public Source +{ +public: + /** + * @brief Construct a new TensorSource object with params + * @param [in] shape Shape of tensor + * @param [in] base Base address + * @param [in] size Size of tensor + */ + TensorSource(const nnfw::misc::tensor::Shape &shape, const T *base, const size_t size) + : _shape{shape}, _base{base}, _size{size} + { + // DO NOTHING + } + +public: + /** + * @brief Function for pushing tensor + * @param [in] tensor Tensor to be pushed + * @return N/A + */ + void push(::arm_compute::ITensor &tensor) const override + { + const ::internal::nnapi::tensor::Reader<T> from{_shape, _base, _size}; + ::internal::arm_compute::tensor::View<T> into{&tensor}; + + ::nnfw::misc::tensor::iterate(_shape) << [&](const nnfw::misc::tensor::Index &index_nnapi) { + const auto rank = index_nnapi.rank(); + nnfw::misc::tensor::Index index_ACL(rank); + + for (uint32_t axis = 0; axis < rank; ++axis) + { + index_ACL.at(ToARMComputeAxis(rank, axis).value()) = index_nnapi.at(axis); + } + + into.at(index_ACL) = from.at(index_nnapi); + }; + } + +private: + const nnfw::misc::tensor::Shape _shape; + const T *const _base; + const size_t _size; +}; + +#endif // __INTERNAL_TENSOR_SOURCE_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/VectorSink.h b/runtime/contrib/pure_arm_compute/src/internal/VectorSink.h new file mode 100644 index 000000000..a630ef1c1 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/VectorSink.h @@ -0,0 +1,73 @@ +/* + * 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. + */ + +/** + * @file       VectorSink.h + * @brief      This file contains VectorSink class + * @ingroup    COM_AI_RUNTIME + */ + +#ifndef __INTERNAL_VECTOR_SINK_H__ +#define __INTERNAL_VECTOR_SINK_H__ + +#include "internal/Sink.h" + +#include <arm_compute/core/ITensor.h> + +#include <cassert> + +/** + * @brief Class to store vector(2D) output data. + * This is for pulling out the data to another tensor. + * @tparam T Type of the data elements + */ +template <typename T> class VectorSink final : public Sink +{ +public: + /** + * @brief Construct a VectorSink object + * @param[in] vlen Length of the vector + * @param[in] base Base pointer of the actual data + * @param[in] size Size of the data + */ + VectorSink(const int32_t vlen, T *base, const size_t size) : _vlen{vlen}, _base{base} + { + assert(size >= _vlen * sizeof(T)); + } + +public: + /** + * @brief Pull the data into the internal structure + * @param[in] tensor The tensor which contains source data + * @return N/A + */ + void pull(::arm_compute::ITensor &tensor) const override + { + for (int32_t n = 0; n < _vlen; ++n) + { + auto from = reinterpret_cast<T *>(tensor.ptr_to_element(::arm_compute::Coordinates{n})); + auto into = _base + n; + + *into = *from; + } + } + +private: + const int32_t _vlen; + T *const _base; +}; + +#endif // __INTERNAL_VECTOR_SINK_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/VectorSource.h b/runtime/contrib/pure_arm_compute/src/internal/VectorSource.h new file mode 100644 index 000000000..48d3d3209 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/VectorSource.h @@ -0,0 +1,69 @@ +/* + * 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. + */ + +/** + * @file       VectorSource.h + * @brief      This file contains VectorSource class + * @ingroup    COM_AI_RUNTIME + */ + +#ifndef __INTERNAL_VECTOR_SOURCE_H__ +#define __INTERNAL_VECTOR_SOURCE_H__ + +#include "internal/Source.h" + +/** + * @brief Class to store vector(2D) input data. + * This is for push out the data to another tensor. + * @tparam T Type of the data elements + */ +template <typename T> class VectorSource final : public Source +{ +public: + /** + * @brief Construct a VectorSource object + * @param[in] vlen Length of the vector + * @param[in] base Base pointer of the actual data + * @param[in] size Size of the data + */ + VectorSource(const int32_t vlen, const T *base, const size_t size) : _vlen{vlen}, _base{base} + { + assert(size >= _vlen * sizeof(T)); + } + +public: + /** + * @brief Push the data out to the another tensor + * @param[out] The tensor that output data will be stored + * @return N/A + */ + void push(::arm_compute::ITensor &tensor) const override + { + for (int32_t n = 0; n < _vlen; ++n) + { + auto from = _base + n; + auto into = reinterpret_cast<T *>(tensor.ptr_to_element(::arm_compute::Coordinates{n})); + + *into = *from; + } + } + +private: + const int32_t _vlen; + const T *const _base; +}; + +#endif // __INTERNAL_VECTOR_SOURCE_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/arm_compute.cc b/runtime/contrib/pure_arm_compute/src/internal/arm_compute.cc new file mode 100644 index 000000000..a7be2068d --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/arm_compute.cc @@ -0,0 +1,87 @@ +/* + * 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 "internal/arm_compute.h" + +#include <arm_compute/runtime/CL/CLScheduler.h> + +#include <cassert> + +namespace internal +{ +namespace arm_compute +{ +namespace operand +{ + +void Object::access(const std::function<void(::arm_compute::ITensor &tensor)> &fn) const +{ + if (::internal::arm_compute::isGpuMode()) + { + auto &queue = ::arm_compute::CLScheduler::get().queue(); + + auto cl_tensor = _tensor.get(); + CAST_CL(cl_tensor)->map(queue); + fn(*_tensor); + CAST_CL(cl_tensor)->unmap(queue); + } + else + { + fn(*_tensor); + } +} + +} // namespace operand +} // namepsace arm_compute +} // namespace internal + +namespace internal +{ +namespace arm_compute +{ +namespace operand +{ + +Context &Context::set(const ::internal::tflite::operand::Index &id, + const std::shared_ptr<::arm_compute::ITensor> &tensor) +{ + assert(_objects.find(id.asInt()) == _objects.end()); + + _objects[id.asInt()] = Object{tensor}; + return (*this); +} + +} // namespace operand +} // namepsace arm_compute +} // namespace internal + +namespace internal +{ +namespace arm_compute +{ + +bool isGpuMode() +{ + char *neon = std::getenv("NEON"); + if (neon == nullptr) + return true; + else if (neon[0] == '1') + return false; + return true; +} + +} // namepsace arm_compute +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/arm_compute.h b/runtime/contrib/pure_arm_compute/src/internal/arm_compute.h new file mode 100644 index 000000000..fb6acaf81 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/arm_compute.h @@ -0,0 +1,337 @@ +/* + * 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. + */ + +/** + * @file       arm_compute.h + * @brief      This file contains arm_compute library related classes + * @ingroup    COM_AI_RUNTIME + */ + +#ifndef __INTERNAL_ARM_COMPUTE_H__ +#define __INTERNAL_ARM_COMPUTE_H__ + +#include <arm_compute/core/ITensor.h> +#include <arm_compute/runtime/CL/CLTensor.h> +#include <arm_compute/runtime/Tensor.h> + +namespace internal +{ +namespace arm_compute +{ +namespace operand +{ + +/** + * @brief Class to access the tensor object + */ +class Object +{ +public: + Object() = default; + +public: + Object(const std::shared_ptr<::arm_compute::ITensor> &tensor) : _tensor{tensor} + { + // DO NOTHING + } + +public: + /** + * @brief Get the tensor pointer + * @return The tensor pointer + */ + ::arm_compute::ITensor *ptr(void) const { return _tensor.get(); } + +private: + std::shared_ptr<::arm_compute::ITensor> _tensor; + +public: + /** + * @brief Access the tensor object and run the given function + : @param[in] fn The actual behavior when accessing the tensor object + * @return N/A + */ + void access(const std::function<void(::arm_compute::ITensor &tensor)> &fn) const; +}; + +} // namespace operand +} // namepsace arm_compute +} // namespace internal + +#include "internal/Model.h" + +#include <map> + +namespace internal +{ +namespace arm_compute +{ +namespace operand +{ + +/** + * @brief Class to manage Object instances + */ +class Context +{ +public: + /** + * @brief Set index and tensor pair + * @param[in] ind The operand index + * @param[in] tensor The tensor object + * @return This object reference + */ + Context &set(const ::internal::tflite::operand::Index &ind, + const std::shared_ptr<::arm_compute::ITensor> &tensor); + +public: + /** + * @brief Check if the tensor for given index is exist + * @param[in] ind The operand Index + * @return @c true if the entry for ind is exist, otherwise @c false + */ + bool exist(const ::internal::tflite::operand::Index &ind) const + { + return _objects.find(ind.asInt()) != _objects.end(); + } + +public: + /** + * @brief Lookup the tensor with the given index + * @param[in] ind The index as the key + * @return The object const reference + */ + const Object &at(const ::internal::tflite::operand::Index &ind) const + { + return _objects.at(ind.asInt()); + } + + /** + * @brief Lookup the tensor with the given index + * @param[in] ind The index as the key + * @return The object reference + */ + Object &at(const ::internal::tflite::operand::Index &ind) { return _objects.at(ind.asInt()); } + +private: + std::map<int, Object> _objects; +}; + +} // namespace operand +} // namepsace arm_compute +} // namespace internal + +#include <arm_compute/runtime/IFunction.h> + +namespace internal +{ +namespace arm_compute +{ +namespace op +{ + +/** + * @brief Class to wrap IFunction + */ +class Step +{ +public: + /** + * @brief Construct a Step object + * @param[in] func The compiled code to be executed + */ + Step(std::unique_ptr<::arm_compute::IFunction> &&func) : _func{std::move(func)} + { + // DO NOTHING + } + +public: + /** + * @brief Run _func + * @return N/A + */ + void run(void) const { _func->run(); } + +public: + /** + * @brief Get member @c _name + * @return The name as const reference + */ + const std::string &name(void) const { return _name; } + /** + * @brief Get member @c _name + * @return The name as reference + */ + std::string &name(void) { return _name; } + +private: + std::string _name; + std::unique_ptr<::arm_compute::IFunction> _func; +#ifdef TFLITE_PROFILING_ENABLED +public: + /** + * @brief Get member @c _op_index + * @return The operation index as value + */ + int op_idx() const { return _op_idx; } + /** + * @brief Get member @c _op_index + * @return The operation index as reference + */ + int &op_idx() { return _op_idx; } +private: + int _op_idx; +#endif +}; + +} // namespace op +} // namepsace arm_compute +} // namespace internal + +namespace internal +{ +namespace arm_compute +{ +namespace op +{ + +/** + * @brief Class managing compiled operation code Sequence + */ +class Sequence +{ +public: + /** + * @brief Get size of sequence + * @return Number of sequence steps + */ + uint32_t size(void) const { return _functions.size(); } + +public: + /** + * @brief Append a Function to the sequence + * @param[in] func Function to be appended + * @return This object reference + */ + Sequence &append(std::unique_ptr<::arm_compute::IFunction> &&func) + { + _functions.emplace_back(std::move(func)); + return (*this); + } + +public: + /** + * @brief Get the step entry on the index @c n + * @param[in] n The index + * @return The step object as reference + */ + Step &at(uint32_t n) { return _functions.at(n); } + /** + * @brief Get the step entry on the index @c n + * @param[in] n The index + * @return The step object as const reference + */ + const Step &at(uint32_t n) const { return _functions.at(n); } + +private: + // TODO Rename _functions as _steps + std::vector<Step> _functions; +}; + +} // namespace op +} // namepsace arm_compute +} // namespace internal + +namespace internal +{ +namespace arm_compute +{ + +/** + * @brief Class to manage compiled operation sequence + */ +class Plan +{ +public: + /** + * @brief Construct a Plan object + * @param[in] model Model that we want to compile + */ + Plan(const std::shared_ptr<const ::internal::tflite::Model> &model) : _model(model) + { + // DO NOTHING + } + +public: + /** + * @brief Get the model object + * @return The model object as const reference + */ + const ::internal::tflite::Model &model(void) const { return *_model; } + +public: + /** + * @brief Get operand context + * @return The operand context as reference + */ + operand::Context &operands(void) { return _operands; } + /** + * @brief Get operand context + * @return The operand context as const reference + */ + const operand::Context &operands(void) const { return _operands; } + +public: + /** + * @brief Get operation sequence + * @return The operation sequence as reference + */ + op::Sequence &operations(void) { return _ops; } + /** + * @brief Get operation sequence + * @return The operation sequence as const reference + */ + const op::Sequence &operations(void) const { return _ops; } + +private: + std::shared_ptr<const ::internal::tflite::Model> _model; + operand::Context _operands; + op::Sequence _ops; +}; + +} // namepsace arm_compute +} // namespace internal + +#include <arm_compute/core/ITensor.h> + +namespace internal +{ +namespace arm_compute +{ + +/** + * @brief Check if this runtime runs on GPU or NEON + * @return @c true if GPU mode, otherwise @c false + */ +bool isGpuMode(); + +#define CAST_CL(tensor) static_cast<::arm_compute::CLTensor *>(tensor) +#define CAST_NE(tensor) static_cast<::arm_compute::Tensor *>(tensor) + +} // namepsace arm_compute +} // namespace internal + +#endif // __INTERNAL_ARM_COMPUTE_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/arm_compute/Cast.cc b/runtime/contrib/pure_arm_compute/src/internal/arm_compute/Cast.cc new file mode 100644 index 000000000..1a5c735ee --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/arm_compute/Cast.cc @@ -0,0 +1,152 @@ +/* + * 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 "internal/arm_compute/Cast.h" + +#include "internal/Swizzle.h" + +::arm_compute::Coordinates getARMComputeAxises(uint32_t rank) +{ + ::arm_compute::Coordinates res{}; + + res.set_num_dimensions(rank); + + for (uint32_t axis = 0; axis < rank; ++axis) + { + res.set(axis, ToARMComputeAxis(rank, axis).value()); + } + + return res; +} + +::arm_compute::Coordinates asARMComputeCoordinates(const ::arm_compute::Coordinates &runtime_coord, + const ::arm_compute::Coordinates &axises) +{ + ::arm_compute::Coordinates id{}; + assert(runtime_coord.num_dimensions() == axises.num_dimensions()); + for (size_t i = 0; i < runtime_coord.num_dimensions(); ++i) + { + id.set(axises[i], runtime_coord[i]); + } + return id; +} + +// Restructure runtime_permutationVector to ACL_permutationVector +::arm_compute::PermutationVector getARMComputePermutationVector(uint32_t rank, + const int32_t *runtime_pv) +{ + // rank upto 4 is supported + assert(rank <= 4); + assert(runtime_pv != nullptr); + + int new_pv[4] = {0}; + ::arm_compute::Coordinates axises = getARMComputeAxises(rank); + + for (uint32_t i = 0; i < rank; ++i) + { + new_pv[axises[i]] = ToARMComputeAxis(rank, runtime_pv[i]).value(); + } + + ::arm_compute::PermutationVector ACL_PV = + ::arm_compute::PermutationVector{new_pv[0], new_pv[1], new_pv[2], new_pv[3]}; + ACL_PV.set_num_dimensions(rank); + + return ACL_PV; +} + +::arm_compute::TensorShape asTensorShape(const internal::tflite::operand::Shape &shape, + bool apply_dim_correction) +{ + const uint32_t rank = shape.rank(); + + ::arm_compute::TensorShape res{}; + + res.set_num_dimensions(rank); + + for (uint32_t axis = 0; axis < rank; ++axis) + { + // NOTE In some cases, in incorrect dimensions is required. + // For example, intput_size is 1 in LSTM. The input-to-input weights([num_units, input_size]) of + // LSTM is used as the weight of the FullyConnected. + // The FullyConnected's weight must be greater or equal than 2-dimensions. + // However, if the dimension correction is applied to input_to_input_weights with input_size + // equal to 1, it will be changed to 1-D. + // So input_to_input_weights is not used by the weight of FullyConnected. + res.set(ToARMComputeAxis(rank, axis).value(), shape.dim(axis), apply_dim_correction); + } + + return res; +} + +::arm_compute::DataType asDataType(const int32_t type) +{ + switch (type) + { + case ANEURALNETWORKS_FLOAT32: + case ANEURALNETWORKS_TENSOR_FLOAT32: + return ::arm_compute::DataType::F32; + case ANEURALNETWORKS_INT32: + case ANEURALNETWORKS_TENSOR_INT32: + return ::arm_compute::DataType::S32; + case ANEURALNETWORKS_UINT32: + return ::arm_compute::DataType::U32; + case ANEURALNETWORKS_TENSOR_QUANT8_ASYMM: + return ::arm_compute::DataType::QASYMM8; + default: + throw std::runtime_error("Not supported, yet"); + break; + } +} + +::arm_compute::ActivationLayerInfo asActivationInfo(FuseCode code) +{ + switch (code) + { + case ANEURALNETWORKS_FUSED_NONE: + return ::arm_compute::ActivationLayerInfo{}; + case ANEURALNETWORKS_FUSED_RELU: + return ::arm_compute::ActivationLayerInfo{ + ::arm_compute::ActivationLayerInfo::ActivationFunction::RELU}; + case ANEURALNETWORKS_FUSED_RELU1: + return ::arm_compute::ActivationLayerInfo{ + ::arm_compute::ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, 1.0f, -1.0f}; + case ANEURALNETWORKS_FUSED_RELU6: + return ::arm_compute::ActivationLayerInfo{ + ::arm_compute::ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, 6.0f, 0.0f}; + default: + throw std::runtime_error("Not supported, yet"); + break; + } +} + +::arm_compute::QuantizationInfo asQuantizationInfo(const float scale, const int32_t offset) +{ + return ::arm_compute::QuantizationInfo(scale, offset); +} + +::arm_compute::TensorInfo asTensorInfo(const ::arm_compute::TensorShape &shape, const int32_t type, + const float scale, const int32_t zeroPoint) +{ + return ::arm_compute::TensorInfo(shape, 1, asDataType(type), + asQuantizationInfo(scale, zeroPoint)); +} + +::arm_compute::TensorInfo asTensorInfo(const ::arm_compute::TensorShape &shape, + const ::arm_compute::DataType &type, const float scale, + const int32_t zeroPoint) +{ + return ::arm_compute::TensorInfo(shape, 1, type, asQuantizationInfo(scale, zeroPoint)); +} diff --git a/runtime/contrib/pure_arm_compute/src/internal/arm_compute/Cast.h b/runtime/contrib/pure_arm_compute/src/internal/arm_compute/Cast.h new file mode 100644 index 000000000..211a6ac87 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/arm_compute/Cast.h @@ -0,0 +1,156 @@ +/* + * 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. + */ + +/** + * @file Cast.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines casting functions from internal object to arm compute object + */ +#ifndef __ARM_COMPUTE_CAST_H__ +#define __ARM_COMPUTE_CAST_H__ + +#include <arm_compute/core/Coordinates.h> +#include <arm_compute/core/TensorInfo.h> +#include <arm_compute/core/TensorShape.h> +#include <arm_compute/core/Types.h> + +#include <NeuralNetworks.h> + +#include "internal/Model.h" + +/** + * @brief Generate arm compute coordinate object from rank + * @param[in] rank Rank number + * @return Coordinate object + */ +::arm_compute::Coordinates getARMComputeAxises(uint32_t rank); + +/** + * @brief Generate arm compute coordinate object from runtime coordinate object + * @param[in] runtime_coord Runtime coordinates object + * @param[in] axises Coordinates for axises to map runtime-coordinates to + * arm_compute-coordinates + * @return Arm_compute coordinate object + */ +::arm_compute::Coordinates asARMComputeCoordinates(const ::arm_compute::Coordinates &runtime_coord, + const ::arm_compute::Coordinates &axises); + +/** +* @brief Generate arm compute permutation vector from runtime permutation vector +* @param[in] rank Rank number supported upto 4 +* @param[in] runtime_pv Integer array for runtime permutation vector +* @return Permutation vector of arm compute +*/ +::arm_compute::PermutationVector getARMComputePermutationVector(uint32_t rank, + const int32_t *runtime_pv); +/** + * @brief Cast from shape of internal to arm compute + * @param[in] shape Internal shape object + * @param[in] apply_dim_correction Flag to state whether apply dimension correction after setting + * one dimension in arm compute + * @return TensorShape object of arm compute + */ +::arm_compute::TensorShape asTensorShape(const internal::tflite::operand::Shape &shape, + bool apply_dim_correction = true); + +/** + * @brief Cast from data type enum of NNAPI to arm compute + * @param[in] type NNAPI data type + * @return Data type of arm compute + */ +::arm_compute::DataType asDataType(const int32_t type); + +/** + * @brief Cast from NNAPI activation type enum to activation object of arm compute + * @param[in] code NNAPI activation type + * @return ActivationLayerInfo object of arm compute + */ +::arm_compute::ActivationLayerInfo asActivationInfo(FuseCode code); + +/** + * @brief Generate quantization info object of arm compute + * @param[in] scale Scale of quantization + * @param[in] offset Offset of quantization + * @return QuantizationInfo object of arm compute + */ +::arm_compute::QuantizationInfo asQuantizationInfo(const float scale, const int32_t offset); + +/** + * @brief Cast from internal tensor info to tensor info object of arm compute + * @param[in] shape Tensor shape + * @param[in] type Tensor type + * @param[in] scale Scale of tensor quantization + * @param[in] zeroPoint Zeropoint of tensor quantization + * @return TensorInfo object of arm compute + */ +::arm_compute::TensorInfo asTensorInfo(const ::arm_compute::TensorShape &shape, const int32_t type, + const float scale = 0.0f, const int32_t zeroPoint = 0); + +/** + * @brief Cast from internal tensor info to tensor info object of arm compute + * @param[in] shape Tensor shape + * @param[in] type Tensor type of arm compute + * @param[in] scale Scale of tensor quantization + * @param[in] zeroPoint Zeropoint of tensor quantization + * @return TensorInfo object of arm compute + */ +::arm_compute::TensorInfo asTensorInfo(const ::arm_compute::TensorShape &shape, + const ::arm_compute::DataType &type, const float scale, + const int32_t zeroPoint); + +/** + * @brief Set value to arm compute tensor with casting + * @param[in] value Value to set + * @param[out] to Target tensor of arm compute + * @param[in] id Position of element + * @return N/A + */ +template <typename FromT> +void copyCast(const FromT value, ::arm_compute::ITensor *to, const ::arm_compute::Coordinates &id) +{ + switch (to->info()->data_type()) + { + case ::arm_compute::DataType::F32: + { + *reinterpret_cast<float *>(to->ptr_to_element(id)) = static_cast<float>(value); + break; + } + case ::arm_compute::DataType::S32: + { + *reinterpret_cast<int32_t *>(to->ptr_to_element(id)) = static_cast<int32_t>(value); + break; + } + case ::arm_compute::DataType::U32: + { + *reinterpret_cast<uint32_t *>(to->ptr_to_element(id)) = static_cast<uint32_t>(value); + break; + } + case ::arm_compute::DataType::QASYMM8: + { + float realValue = static_cast<float>(value); + // NOTE We haven't known the policy of rounding for quantization. + // So this is set to a temporary value. + *(to->ptr_to_element(id)) = to->info()->quantization_info().quantize( + realValue, ::arm_compute::RoundingPolicy::TO_ZERO); + break; + } + default: + throw std::runtime_error("Not supported, yet"); + break; + } +} + +#endif // __ARM_COMPUTE_CAST_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/arm_compute/feature/View.h b/runtime/contrib/pure_arm_compute/src/internal/arm_compute/feature/View.h new file mode 100644 index 000000000..c989ef4c2 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/arm_compute/feature/View.h @@ -0,0 +1,156 @@ +/* + * 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. + */ + +/** + * @file View.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines internal::arm_compute::feature::View class + */ +#ifndef __INTERNAL_ARM_COMPUTE_FEATURE_VIEW_H__ +#define __INTERNAL_ARM_COMPUTE_FEATURE_VIEW_H__ + +#include "misc/feature/Reader.h" + +#include <arm_compute/core/ITensor.h> + +namespace internal +{ +namespace arm_compute +{ +namespace feature +{ + +/** + * @brief Class to access feature's element + */ +template <typename T> class View final : public nnfw::misc::feature::Reader<T> +{ +public: + /** + * @brief Construct a new View object + * @param[in] tensor Feature to support access + */ + View(::arm_compute::ITensor *tensor) : _tensor{tensor} + { + // DO NOTHING + } + +public: + /** + * @brief Get value of element in 3D feature using channel, row and column + * @param[in] ch Channel index + * @param[in] row Row index + * @param[in] col Column index + * @return Value of element + */ + T at(uint32_t ch, uint32_t row, uint32_t col) const override + { + const auto offset = feature_index_to_byte_offset(ch, row, col); + + T *ptr = reinterpret_cast<T *>(_tensor->buffer() + offset); + + return *ptr; + } + + /** + * @brief Get value of element in 4D feature using batch, channel, row and column + * @param[in] batch Batch index + * @param[in] ch Channel index + * @param[in] row Row index + * @param[in] col Column index + * @return Value of element + */ + T at(uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) const override + { + const auto offset = feature_index_to_byte_offset(batch, ch, row, col); + + T *ptr = reinterpret_cast<T *>(_tensor->buffer() + offset); + + return *ptr; + } + +public: + /** + * @brief Get reference of element in 3D feature using channel, row and column + * @param[in] ch Channel index + * @param[in] row Row index + * @param[in] col Column index + * @return Reference of element + */ + T &at(uint32_t ch, uint32_t row, uint32_t col) + { + const auto offset = feature_index_to_byte_offset(ch, row, col); + + T *ptr = reinterpret_cast<T *>(_tensor->buffer() + offset); + + return *ptr; + } + + /** + * @brief Get reference of element in 4D feature using batch, channel, row and column + * @param[in] batch Batch index + * @param[in] ch Channel index + * @param[in] row Row index + * @param[in] col Column index + * @return Reference of element + */ + T &at(uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) + { + const auto offset = feature_index_to_byte_offset(batch, ch, row, col); + + T *ptr = reinterpret_cast<T *>(_tensor->buffer() + offset); + + return *ptr; + } + +private: + /** + * @brief Get offset of element in 3D feature + * @param[in] ch Channel index + * @param[in] row Row index + * @param[in] col Column index + * @return Offset of element + */ + size_t feature_index_to_byte_offset(uint32_t ch, uint32_t row, uint32_t col) const + { + // ARM Compute uses CHW ordering + return _tensor->info()->offset_element_in_bytes(::arm_compute::Coordinates{col, row, ch}); + } + + /** + * @brief Get offset of element in 4D feature + * @param[in] batch Batch index + * @param[in] ch Channel index + * @param[in] row Row index + * @param[in] col Column index + * @return Offset of element + */ + size_t feature_index_to_byte_offset(uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) const + { + // ARM Compute uses CHW ordering + return _tensor->info()->offset_element_in_bytes( + ::arm_compute::Coordinates{col, row, ch, batch}); + } + +private: + ::arm_compute::ITensor *_tensor; +}; + +} // namespace feature +} // namespace arm_compute +} // namespace internal + +#endif // __INTERNAL_ARM_COMPUTE_FEATURE_VIEW_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/arm_compute/kernel/View.h b/runtime/contrib/pure_arm_compute/src/internal/arm_compute/kernel/View.h new file mode 100644 index 000000000..399cdf913 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/arm_compute/kernel/View.h @@ -0,0 +1,110 @@ +/* + * 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. + */ + +/** + * @file View.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines internel::arm_compute::kernel::View class + */ +#ifndef __INTERNAL_ARM_COMPUTE_KERNEL_VIEW_H__ +#define __INTERNAL_ARM_COMPUTE_KERNEL_VIEW_H__ + +#include "misc/kernel/Shape.h" +#include "misc/kernel/Reader.h" + +#include <arm_compute/core/ITensor.h> + +namespace internal +{ +namespace arm_compute +{ +namespace kernel +{ + +/** + * @brief Class to access kernel's element + */ +template <typename T> class View final : public nnfw::misc::kernel::Reader<T> +{ +public: + /** + * @brief Construct a new View object + * @param[in] tensor Kernel to support access + */ + View(::arm_compute::ITensor *tensor) : _tensor{tensor} + { + // DO NOTHING + } + +public: + /** + * @brief Get value of element in kernel + * @param[in] nth Kernel index + * @param[in] ch Channel index + * @param[in] row Row index + * @param[in] col Column index + * @return Value of element + */ + T at(uint32_t nth, uint32_t ch, uint32_t row, uint32_t col) const override + { + const auto offset = kernel_index_to_byte_offset(nth, ch, row, col); + + T *ptr = reinterpret_cast<T *>(_tensor->buffer() + offset); + + return *ptr; + } + +public: + /** + * @brief Get reference of element in kernel + * @param[in] nth Kernel index + * @param[in] ch Channel index + * @param[in] row Row index + * @param[in] col Column index + * @return Reference of element + */ + T &at(uint32_t nth, uint32_t ch, uint32_t row, uint32_t col) + { + const auto offset = kernel_index_to_byte_offset(nth, ch, row, col); + + T *ptr = reinterpret_cast<T *>(_tensor->buffer() + offset); + + return *ptr; + } + +private: + /** + * @brief Get offset of element in kernel + * @param[in] nth Kernel index + * @param[in] ch Channel index + * @param[in] row Row index + * @param[in] col Column index + * @return Offset of element + */ + size_t kernel_index_to_byte_offset(uint32_t nth, uint32_t ch, uint32_t row, uint32_t col) const + { + return _tensor->info()->offset_element_in_bytes(::arm_compute::Coordinates{col, row, ch, nth}); + } + +private: + ::arm_compute::ITensor *_tensor; +}; + +} // namespace kernel +} // namespace arm_compute +} // namespace internal + +#endif // __INTERNAL_ARM_COMPUTE_FEATURE_VIEW_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/arm_compute/matrix/View.h b/runtime/contrib/pure_arm_compute/src/internal/arm_compute/matrix/View.h new file mode 100644 index 000000000..305fff729 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/arm_compute/matrix/View.h @@ -0,0 +1,104 @@ +/* + * 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. + */ + +/** + * @file View.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines internal::arm_compute::matrix::View class + */ +#ifndef __INTERNAL_ARM_COMPUTE_MATRIX_VIEW_H__ +#define __INTERNAL_ARM_COMPUTE_MATRIX_VIEW_H__ + +#include "misc/matrix/Shape.h" +#include "misc/matrix/Reader.h" + +#include <arm_compute/core/ITensor.h> + +namespace internal +{ +namespace arm_compute +{ +namespace matrix +{ + +/** + * @brief Class to access matrix's element + */ +template <typename T> class View final : public nnfw::misc::matrix::Reader<T> +{ +public: + /** + * @brief Construct a new View object + * @param[in] tensor Matrix to support access + */ + View(::arm_compute::ITensor *tensor) : _tensor{tensor} + { + // DO NOTHING + } + +public: + /** + * @brief Get value of element in matrix + * @param[in] row Row index + * @param[in] col Column index + * @return Value of element + */ + T at(uint32_t row, uint32_t col) const override + { + const auto offset = matrix_index_to_byte_offset(row, col); + + T *ptr = reinterpret_cast<T *>(_tensor->buffer() + offset); + + return *ptr; + } + +public: + /** + * @brief Get reference of element in matrix + * @param[in] row Row index + * @param[in] col Column index + * @return Refence of element + */ + T &at(uint32_t row, uint32_t col) + { + const auto offset = matrix_index_to_byte_offset(row, col); + + T *ptr = reinterpret_cast<T *>(_tensor->buffer() + offset); + + return *ptr; + } + +private: + /** + * @brief Get offset of element in matrix + * @param[in] row Row index + * @param[in] col Column index + * @return Offset of element + */ + size_t matrix_index_to_byte_offset(uint32_t row, uint32_t col) const + { + return _tensor->info()->offset_element_in_bytes(::arm_compute::Coordinates{col, row}); + } + +private: + ::arm_compute::ITensor *_tensor; +}; + +} // namespace matrix +} // namespace arm_compute +} // namespace internal + +#endif // __INTERNAL_ARM_COMPUTE_MATRIX_VIEW_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/arm_compute/tensor/View.h b/runtime/contrib/pure_arm_compute/src/internal/arm_compute/tensor/View.h new file mode 100644 index 000000000..372bd682d --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/arm_compute/tensor/View.h @@ -0,0 +1,112 @@ +/* + * 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. + */ + +/** + * @file View.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines internal::arm_compute::tensor::View class + */ +#ifndef __INTERNAL_ARM_COMPUTE_TENSOR_VIEW_H__ +#define __INTERNAL_ARM_COMPUTE_TENSOR_VIEW_H__ + +#include "misc/tensor/Shape.h" +#include "misc/tensor/Index.h" + +#include <arm_compute/core/ITensor.h> + +namespace internal +{ +namespace arm_compute +{ +namespace tensor +{ + +/** + * @brief Class to access tensor's element + */ +template <typename T> class View +{ +public: + /** + * @brief Construct a new View object + * @param[in] tensor Tensor to support access + */ + View(::arm_compute::ITensor *tensor) : _tensor{tensor} + { + // DO NOTHING + } + +private: + /** + * @brief Get offset of element in tensor + * @param[in] index Index of element + * @return Offset of element + */ + uint32_t byte_offset_of(const nnfw::misc::tensor::Index &index) const + { + // NOTE index.rank() >= _tensor->info()->num_dimensions() should hold here + const uint32_t rank = index.rank(); + + ::arm_compute::Coordinates coordinates; + + coordinates.set_num_dimensions(rank); + + for (uint32_t axis = 0; axis < rank; ++axis) + { + coordinates[axis] = index.at(axis); + } + + return _tensor->info()->offset_element_in_bytes(coordinates); + } + +public: + /** + * @brief Get value of element in tensor + * @param[in] index Index of element + * @return Value of element + */ + T at(const nnfw::misc::tensor::Index &index) const + { + const auto offset = byte_offset_of(index); + + T *ptr = reinterpret_cast<T *>(_tensor->buffer() + offset); + + return *ptr; + } + + /** + * @brief Get reference of element in tensor + * @param[in] index Index of element + * @return Reference of element + */ + T &at(const nnfw::misc::tensor::Index &index) + { + const auto offset = byte_offset_of(index); + + T *ptr = reinterpret_cast<T *>(_tensor->buffer() + offset); + + return *ptr; + } + +private: + ::arm_compute::ITensor *_tensor; +}; + +} // namespace tensor +} // namespace arm_compute +} // namespace internal + +#endif // __INTERNAL_ARM_COMPUTE_TENSOR_VIEW_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/nnapi/feature/Reader.h b/runtime/contrib/pure_arm_compute/src/internal/nnapi/feature/Reader.h new file mode 100644 index 000000000..ac25692a1 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/nnapi/feature/Reader.h @@ -0,0 +1,105 @@ +/* + * 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. + */ + +/** + * @file Reader.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines internal::nnapi::feature::Reader + */ +#ifndef __INTERNAL_NNAPI_FEATURE_READER_H__ +#define __INTERNAL_NNAPI_FEATURE_READER_H__ + +#include "internal/nnapi/feature/Utils.h" + +#include "misc/feature/Reader.h" + +namespace internal +{ +namespace nnapi +{ +namespace feature +{ + +/** + * @brief Class to support reading element in feature(3D, 4D) + */ +template <typename T> class Reader final : public nnfw::misc::feature::Reader<T> +{ +public: + /** + * @brief Construct a new Reader object + * @param[in] shape Shape of feature + * @param[in] ptr Pointer to feature data + * @param[in] len Size of tensor (byte) + */ + // NOTE The parameter len denotes the number of bytes. + Reader(const ::nnfw::misc::feature::Shape &shape, const T *ptr, size_t len) + : _shape{shape}, _ptr{ptr} + { + assert(shape.N * shape.C * shape.H * shape.W * sizeof(T) == len); + } + +public: + /** + * @brief Get shape of feature + * @return Shape of feature + */ + const nnfw::misc::feature::Shape &shape(void) const { return _shape; } + +public: + /** + * @brief Get value of element using channel, row, and column index for 3D feature + * @param[in] ch Channel index + * @param[in] row Row index + * @param[in] col Column index + * @return Value of element + */ + T at(uint32_t ch, uint32_t row, uint32_t col) const override + { + uint32_t index = index_of(_shape, ch, row, col); + + const auto arr = reinterpret_cast<const T *>(_ptr); + + return arr[index]; + } + + /** + * @brief Get value of element using batch, channel, row, and column index for 4D feature + * @param[in] batch Batch index + * @param[in] ch Channel index + * @param[in] row Row index + * @param[in] col Column index + * @return Value of element + */ + T at(uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) const override + { + uint32_t index = index_of(_shape, batch, ch, row, col); + + return _ptr[index]; + } + +private: + nnfw::misc::feature::Shape _shape; + +private: + const T *_ptr; +}; + +} // namespace feature +} // namespace nnapi +} // namespace internal + +#endif // __INTERNAL_NNAPI_FEATURE_READER_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/nnapi/feature/Utils.h b/runtime/contrib/pure_arm_compute/src/internal/nnapi/feature/Utils.h new file mode 100644 index 000000000..ee59d217e --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/nnapi/feature/Utils.h @@ -0,0 +1,82 @@ +/* + * 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. + */ + +/** + * @file Utils.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines utility functions used in internal::nnapi::feature namespace + */ +#ifndef __INTERNAL_NNAPI_FEATURE_UTILS_H__ +#define __INTERNAL_NNAPI_FEATURE_UTILS_H__ + +#include "misc/feature/Shape.h" + +namespace internal +{ +namespace nnapi +{ +namespace feature +{ + +/** + * @brief Get position of element using channel, row, and column for 3D feature + * @param[in] shape Shape of feature + * @param[in] ch Channel index + * @param[in] row Row index + * @param[in] col Column index + * @return Position of element + */ +inline uint32_t index_of(const ::nnfw::misc::feature::Shape &shape, uint32_t ch, uint32_t row, + uint32_t col) +{ + uint32_t res = 0; + + // NNAPI uses NHWC ordering + res += row * shape.W * shape.C; + res += col * shape.C; + res += ch; + + return res; +} + +/** + * @brief Get position of element using batch, channel, row, and column for 4D feature + * @param[in] shape Shape of feature + * @param[in] batch Batch index + * @param[in] ch Channel index + * @param[in] row Row index + * @param[in] col Column index + * @return Position of element + */ +inline uint32_t index_of(const ::nnfw::misc::feature::Shape &shape, uint32_t batch, uint32_t ch, + uint32_t row, uint32_t col) +{ + uint32_t res = 0; + + // NNAPI uses NHWC ordering + res += batch * shape.H * shape.W * shape.C; + res += row * shape.W * shape.C; + res += col * shape.C; + res += ch; + + return res; +} + +} // namespace feature +} // namespace nnapi +} // namespace internal + +#endif // __INTERNAL_NNAPI_FEATURE_UTILS_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/nnapi/feature/View.h b/runtime/contrib/pure_arm_compute/src/internal/nnapi/feature/View.h new file mode 100644 index 000000000..965e42f1c --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/nnapi/feature/View.h @@ -0,0 +1,132 @@ +/* + * 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. + */ + +/** + * @file View.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines internal::nnapi::feature::View class + */ +#ifndef __INTERNAL_NNAPI_FEATURE_VIEW_H__ +#define __INTERNAL_NNAPI_FEATURE_VIEW_H__ + +#include "internal/nnapi/feature/Utils.h" + +#include "misc/feature/Reader.h" + +namespace internal +{ +namespace nnapi +{ +namespace feature +{ + +/** + * @brief Class to access feature's element information using index + */ +template <typename T> class View final : public nnfw::misc::feature::Reader<T> +{ +public: + /** + * @brief Construct a new View object + * @param[in] shape Shape of feature + * @param[in] ptr Pointer to feature data + * @param[in] len Size of feature (byte) + * @return + */ + // NOTE The parameter len denotes the number of bytes. + View(const ::nnfw::misc::feature::Shape &shape, T *ptr, size_t len) : _shape{shape}, _ptr{ptr} + { + assert(shape.N * shape.C * shape.H * shape.W * sizeof(T) == len); + } + +public: + /** + * @brief Get shape of feature + * @return Shape of feature + */ + const nnfw::misc::feature::Shape &shape(void) const { return _shape; } + +public: + /** + * @brief Get value of element in 3D feature using channel, row, and column index + * @param[in] ch Channel index + * @param[in] row Row index + * @param[in] col Column index + * @return Value of element + */ + T at(uint32_t ch, uint32_t row, uint32_t col) const override + { + uint32_t index = index_of(_shape, ch, row, col); + + return _ptr[index]; + } + + /** + * @brief Get value of element in 4D feature using batch, channel, row and column index + * @param[in] batch Batch index + * @param[in] ch Channel index + * @param[in] row Row index + * @param[in] col Column index + * @return Value of element + */ + T at(uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) const override + { + uint32_t index = index_of(_shape, batch, ch, row, col); + + return _ptr[index]; + } + + /** + * @brief Get reference of element in 3D feature using channel, row, and column index + * @param[in] ch Channel index + * @param[in] row Row index + * @param[in] col Column index + * @return Reference of element + */ + T &at(uint32_t ch, uint32_t row, uint32_t col) + { + uint32_t index = index_of(_shape, ch, row, col); + + return _ptr[index]; + } + + /** + * @brief Get reference of element in 4D feature using batch, channel, row and column index + * @param[in] batch Batch index + * @param[in] ch Channel index + * @param[in] row Row index + * @param[in] col Column index + * @return Reference of element + */ + T &at(uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) + { + uint32_t index = index_of(_shape, batch, ch, row, col); + + return _ptr[index]; + } + +private: + nnfw::misc::feature::Shape _shape; + +private: + T *_ptr; +}; + +} // namespace feature +} // namespace nnapi +} // namespace internal + +#endif // __INTERNAL_NNAPI_FEATURE_VIEW_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/nnapi/kernel/Reader.h b/runtime/contrib/pure_arm_compute/src/internal/nnapi/kernel/Reader.h new file mode 100644 index 000000000..ae964f74c --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/nnapi/kernel/Reader.h @@ -0,0 +1,94 @@ +/* + * 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. + */ + +/** + * @file Reader.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines internal::nnapi::kernel::Reader class + */ +#ifndef __INTERNAL_NNAPI_KERNEL_READER_H__ +#define __INTERNAL_NNAPI_KERNEL_READER_H__ + +#include "misc/kernel/Shape.h" +#include "misc/kernel/Reader.h" + +namespace internal +{ +namespace nnapi +{ +namespace kernel +{ + +/** + * @brief Class to support reading element in kernel + */ +template <typename T> class Reader final : public nnfw::misc::kernel::Reader<T> +{ +public: + /** + * @brief Construct a new Reader object + * @param[in] shape Shape of kernel + * @param[in] ptr Pointer to kernel data + * @param[in] len Size of kernel (byte) + */ + // NOTE The parameter len denotes the number of bytes. + Reader(const ::nnfw::misc::kernel::Shape &shape, const T *ptr, size_t len) + : _shape{shape}, _ptr{ptr} + { + assert(shape.N * shape.C * shape.H * shape.W * sizeof(T) == len); + } + +public: + /** + * @brief Get shape of kernel + * @return Shape of kernel + */ + const nnfw::misc::kernel::Shape &shape(void) const { return _shape; } + +public: + /** + * @brief Get value of element for kernel + * @param[in] nth Kernel index + * @param[in] ch Channel index + * @param[in] row Row index + * @param[in] col Column index + * @return Value of element + */ + T at(uint32_t nth, uint32_t ch, uint32_t row, uint32_t col) const override + { + // NNAPI uses NHWC ordering + uint32_t index = 0; + + index += nth * _shape.H * _shape.W * _shape.C; + index += row * _shape.W * _shape.C; + index += col * _shape.C; + index += ch; + + return _ptr[index]; + } + +private: + nnfw::misc::kernel::Shape _shape; + +private: + const T *_ptr; +}; + +} // namespace kernel +} // namespace nnapi +} // namespace internal + +#endif // __INTERNAL_NNAPI_KERNEL_READER_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/nnapi/matrix/Reader.h b/runtime/contrib/pure_arm_compute/src/internal/nnapi/matrix/Reader.h new file mode 100644 index 000000000..f03a4be31 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/nnapi/matrix/Reader.h @@ -0,0 +1,90 @@ +/* + * 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. + */ + +/** + * @file Reader.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines internal::nnapi::matrix::Reader class + */ +#ifndef __INTERNAL_NNAPI_MATRIX_READER_H__ +#define __INTERNAL_NNAPI_MATRIX_READER_H__ + +#include "misc/matrix/Shape.h" +#include "misc/matrix/Reader.h" + +namespace internal +{ +namespace nnapi +{ +namespace matrix +{ + +/** + * @brief Class to support reading element in matrix + */ +template <typename T> class Reader final : public nnfw::misc::matrix::Reader<T> +{ +public: + /** + * @brief Construct a new Reader object + * @param[in] shape Shape of matrix + * @param[in] ptr Pointer to matrix data + * @param[in] len Size of matrix (byte) + */ + // NOTE The parameter len denotes the number of bytes. + Reader(const ::nnfw::misc::matrix::Shape &shape, const T *ptr, size_t len) + : _shape{shape}, _ptr{ptr} + { + assert(shape.H * shape.W * sizeof(T) == len); + } + +public: + /** + * @brief Get shape of matrix + * @return Shape of matrix + */ + const nnfw::misc::matrix::Shape &shape(void) const { return _shape; } + +public: + /** + * @brief Get value of element for matrix + * @param[in] row Row index + * @param[in] col Column index + * @return Value of element + */ + T at(uint32_t row, uint32_t col) const override + { + // NNAPI uses NHWC ordering + uint32_t index = 0; + + index += row * _shape.W; + index += col; + + return _ptr[index]; + } + +private: + nnfw::misc::matrix::Shape _shape; + +private: + const T *_ptr; +}; + +} // namespace matrix +} // namespace nnapi +} // namespace internal + +#endif // __INTERNAL_NNAPI_MATRIX_READER_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/nnapi/tensor/ConstView.h b/runtime/contrib/pure_arm_compute/src/internal/nnapi/tensor/ConstView.h new file mode 100644 index 000000000..6a3fff646 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/nnapi/tensor/ConstView.h @@ -0,0 +1,111 @@ +/* + * 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. + */ + +/** + * @file       ConstView.h + * @brief      This file contains ConstView class + * @ingroup    COM_AI_RUNTIME + */ + +#ifndef __INTERNAL_NNAPI_TENSOR_CONST_VIEW_H__ +#define __INTERNAL_NNAPI_TENSOR_CONST_VIEW_H__ + +#include "util/tensor/Shape.h" +#include "util/tensor/Index.h" + +namespace internal +{ +namespace nnapi +{ +namespace tensor +{ + +/** + * @brief Wrapper class to read tensor values + * @tparam T The tensor element type + */ +template <typename T> class ConstView +{ +public: + /** + * @brief Construct a ConstView class + * @param[in] shape Tensor shape + * @param[in] ptr The base pointer of actual data + * @param[in] len The number of bytes + */ + ConstView(const ::nnfw::misc::tensor::Shape &shape, const uint8_t *ptr, size_t len) + : _shape{shape}, _ptr{ptr}, _len{len} + { + // DO NOTHING + } + +public: + const nnfw::misc::tensor::Shape &shape(void) const { return _shape; } + +private: + // TODO Make this as a helper function, and share it for both View<T> and ConstView<T> + /** + * @brief Calculate offset for the given tensor index + * @param[in] index Tensor index + * @return The calculated offset + */ + uint32_t offset_of(const nnfw::misc::tensor::Index &index) const + { + if (_shape.rank() == 0) + { + return 0; + } + + uint32_t offset = index.at(0); + + // Stride decreases as axis increases in NNAPI + for (uint32_t axis = 1; axis < _shape.rank(); ++axis) + { + offset *= _shape.dim(axis); + offset += index.at(axis); + } + + return offset; + } + +public: + /** + * @brief Get the value on the given index + * @param[in] index Flattened tensor index + * @return The value on the given index + */ + T at(const nnfw::misc::tensor::Index &index) const + { + const auto offset = offset_of(index); + + const T *arr = reinterpret_cast<const T *>(_ptr); + + return arr[offset]; + } + +private: + const nnfw::misc::tensor::Shape _shape; + +private: + const uint8_t *const _ptr; + const size_t _len; +}; + +} // namespace tensor +} // namespace nnapi +} // namespace internal + +#endif // __INTERNAL_NNAPI_TENSOR_CONST_VIEW_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/nnapi/tensor/Reader.h b/runtime/contrib/pure_arm_compute/src/internal/nnapi/tensor/Reader.h new file mode 100644 index 000000000..fc6d490da --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/nnapi/tensor/Reader.h @@ -0,0 +1,116 @@ +/* + * 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. + */ + +/** + * @file       Reader.h + * @brief      This file contains Reader class + * @ingroup    COM_AI_RUNTIME + */ + +#ifndef __INTERNAL_NNAPI_TENSOR_READER_H__ +#define __INTERNAL_NNAPI_TENSOR_READER_H__ + +#include <vector> +#include "misc/tensor/Reader.h" + +namespace internal +{ +namespace nnapi +{ +namespace tensor +{ + +/** + * @brief Wrapper class to read tensor values + * @tparam T The tensor element type + */ +template <typename T> class Reader final : public nnfw::misc::tensor::Reader<T> +{ +public: + /** + * @brief Construct a Reader class + * @param[in] shape Tensor shape + * @param[in] ptr The base pointer of actual data + * @param[in] len The number of bytes + */ + Reader(const ::nnfw::misc::tensor::Shape &shape, const T *ptr, size_t len) + : _shape{shape}, _ptr{ptr} + { + assert(shape.num_elements() * sizeof(T) == len); + initialize(); + } + +public: + /** + * @brief Get shape object + * @return The shape as const reference + */ + const nnfw::misc::tensor::Shape &shape(void) const { return _shape; } + +public: + /** + * @brief Get the value on the given index + * @param[in] index_nnapi Flattened tensor index + * @return The value on the given index + */ + T at(const nnfw::misc::tensor::Index &index_nnapi) const override + { + uint32_t offset = 0; + + for (int i = 0; i < _shape.rank(); i++) + offset += index_nnapi.at(i) * _stridess.at(i); + + return _ptr[offset]; + } + +private: + /** + * @brief Initializes @c _stridess + * @return N/A + * @note Assuming that shape is [d4, .. , d1] and data is stored at a pointer ptr, + we need to calculate the offset of index [i4, .. i1] as follows: + offset = i4 * (d3 * d2 * d1) + + i3 * (d2 * d1) + + i2 * (d1) + + i1 + So (d4 * d3 * d2 * d1) or (d3 * d2 * d1) or (d2 * d1) happens whenever offset is + calculate. To minimize this repetitive calculation, + _stridess[n] contains _spape[n-1]*_spape[n-2]*_spape[0] + */ + void initialize(void) + { + for (int r = 0; r < _shape.rank(); r++) + { + int elem_count = 1; + for (int k = r + 1; k < _shape.rank(); k++) + elem_count *= _shape.dim(k); + _stridess.emplace_back(elem_count); + } + } + +private: + nnfw::misc::tensor::Shape _shape; + +private: + const T *_ptr; + std::vector<int32_t> _stridess; +}; + +} // namespace tensor +} // namespace nnapi +} // namespace internal + +#endif // __INTERNAL_NNAPI_TENSOR_READER_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/nnapi/tensor/View.h b/runtime/contrib/pure_arm_compute/src/internal/nnapi/tensor/View.h new file mode 100644 index 000000000..4766851b9 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/nnapi/tensor/View.h @@ -0,0 +1,121 @@ +/* + * 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. + */ + +/** + * @file View.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines internal::nnapi::tensor::View class + */ +#ifndef __INTERNAL_NNAPI_TENSOR_VIEW_H__ +#define __INTERNAL_NNAPI_TENSOR_VIEW_H__ + +#include "misc/tensor/Shape.h" +#include "misc/tensor/Index.h" + +namespace internal +{ +namespace nnapi +{ +namespace tensor +{ + +/** + * @brief Class to access tensor's element information using index + */ +template <typename T> class View +{ +public: + /** + * @brief Construct a new View object + * @param[in] shape Shape of tensor + * @param[in] ptr Pointer to tensor data + * @param[in] len Size of tensor (byte) + */ + // NOTE The parameter len denotes the number of bytes. + View(const ::nnfw::misc::tensor::Shape &shape, T *ptr, size_t len) : _shape{shape}, _ptr{ptr} + { + assert(shape.num_elements() * sizeof(T) == len); + } + +public: + /** + * @brief Get shape of tensor + * @return Shape of tensor + */ + const nnfw::misc::tensor::Shape &shape(void) const { return _shape; } + +private: + /** + * @brief Get position of element using index in tensor + * @param[in] index Index of element + * @return Position of element + */ + uint32_t offset_of(const nnfw::misc::tensor::Index &index) const + { + if (_shape.rank() == 0) + { + return 0; + } + + uint32_t offset = index.at(0); + + // Stride decreases as axis increases in NNAPI + for (uint32_t axis = 1; axis < _shape.rank(); ++axis) + { + offset *= _shape.dim(axis); + offset += index.at(axis); + } + + return offset; + } + +public: + /** + * @brief Get value of element at index + * @param[in] index Index of element + * @return Value of element at index + */ + T at(const nnfw::misc::tensor::Index &index) const + { + const auto offset = offset_of(index); + + return _ptr[offset]; + } + + /** + * @brief Get reference of element at index + * @param[in] index Index of element + * @return Reference of element at index + */ + T &at(const nnfw::misc::tensor::Index &index) + { + const auto offset = offset_of(index); + + return _ptr[offset]; + } + +private: + nnfw::misc::tensor::Shape _shape; + +private: + T *_ptr; +}; + +} // namespace tensor +} // namespace nnapi +} // namespace internal + +#endif // __INTERNAL_NNAPI_TENSOR_VIEW_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Abs.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Abs.cc new file mode 100644 index 000000000..e23a9538c --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Abs.cc @@ -0,0 +1,59 @@ +/* + * 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 "internal/op/Abs.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Abs +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace Abs +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Abs +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 1 && outputCount == 1); + + output_index = outputs[0]; + input_index = inputs[0]; +} + +} // namespace Abs +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Abs.h b/runtime/contrib/pure_arm_compute/src/internal/op/Abs.h new file mode 100644 index 000000000..0be8b0205 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Abs.h @@ -0,0 +1,68 @@ +/* + * 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 __INTERNAL_OP_ABS_H__ +#define __INTERNAL_OP_ABS_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Abs +{ + +struct Param +{ + int32_t output_index; + int32_t input_index; + + Param() = default; + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +class Node final : public op::Node +{ +public: + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + virtual ~Node() = default; + +public: + const Param ¶m(void) const { return _param; } + +public: + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace Abs +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_ABS_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Add.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Add.cc new file mode 100644 index 000000000..52803261f --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Add.cc @@ -0,0 +1,67 @@ +/* + * 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 "internal/op/Add.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Add +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace Add +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Add +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 3 && outputCount == 1); + + ofm_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> LHS Tensor Index + // 1 -> RHS Tensor Index + // 2 -> Activation Index + lhs_index = inputs[0]; + rhs_index = inputs[1]; + activation_index = inputs[2]; +} + +} // namespace Add +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Add.h b/runtime/contrib/pure_arm_compute/src/internal/op/Add.h new file mode 100644 index 000000000..a7804a569 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Add.h @@ -0,0 +1,110 @@ +/* + * 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. + */ + +/** + * @file Add.h + * @brief This file contains accept function and params for Add operation + * @ingroup COM_AI_RUNTIME + */ + +#ifndef __INTERNAL_OP_ADD_H__ +#define __INTERNAL_OP_ADD_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Add +{ + +/** + * @brief Struct of Add operation's param + */ +struct Param +{ + int32_t ofm_index; /**< Output format index */ + + int32_t lhs_index; /**< Left hand side index */ + int32_t rhs_index; /**< Right hand side index */ + int32_t activation_index; /**< Activation index */ + + /** + * @brief Construct a new Param object for Add as default + */ + Param() = default; + + /** + * @brief Construct a new Param object for Add with params + * @param [in] inputCount The number of input + * @param [in] inputs Array containing inputs + * @param [in] outputCount The number of output + * @param [in] outputs Array containing outputs + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to define operation node for Add + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new Node object for Add with param + * @param [in] param Parameters for Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Destroy the Node object for Add + */ + virtual ~Node() = default; + +public: + /** + * @brief Get parameters for Add + * @return Parameters of Add + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Function for accepting node for Add + * @param [in] v Node visitor for invoking visit function of Add + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace Add +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_ADD_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/ArgMax.cc b/runtime/contrib/pure_arm_compute/src/internal/op/ArgMax.cc new file mode 100644 index 000000000..485430377 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/ArgMax.cc @@ -0,0 +1,64 @@ +/* + * 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 "internal/op/ArgMax.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace ArgMax +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace ArgMax +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace ArgMax +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 2 && outputCount == 1); + + ofm_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> Input Tensor Index + // 1 -> Axis Tensor Index + ifm_index = inputs[0]; + axis_index = inputs[1]; +} + +} // namespace ArgMax +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/ArgMax.h b/runtime/contrib/pure_arm_compute/src/internal/op/ArgMax.h new file mode 100644 index 000000000..780af2232 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/ArgMax.h @@ -0,0 +1,70 @@ +/* + * 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 __INTERNAL_OP_ARGMAX_H__ +#define __INTERNAL_OP_ARGMAX_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace ArgMax +{ + +struct Param +{ + int32_t ofm_index; + + int32_t ifm_index; + int32_t axis_index; + + Param() = default; + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +class Node final : public op::Node +{ +public: + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + virtual ~Node() = default; + +public: + const Param ¶m(void) const { return _param; } + +public: + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace ArgMax +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_ARGMAX_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/AvgPool2D.cc b/runtime/contrib/pure_arm_compute/src/internal/op/AvgPool2D.cc new file mode 100644 index 000000000..ae4c9411e --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/AvgPool2D.cc @@ -0,0 +1,124 @@ +/* + * 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 "internal/op/AvgPool2D.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace AvgPool2D +{ +namespace Explicit +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace Explicit + +namespace Implicit +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace Implicit +} // namespace AvgPool2D +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace AvgPool2D +{ +namespace Explicit +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 10 && outputCount == 1); + + ofm_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> IFM Tensor Index + // 1 -> Padding_left index + // 2 -> Padding_right index + // 3 -> Padding_top index + // 4 -> Padding_bottom index + // 5 -> Horizontal (over width) Stride Index + // 6 -> Vertial (over height) Stride Index + // 7 -> Filter Width Index + // 8 -> Filter Height Index + // 9 -> FuseCode (activation) Index + ifm_index = inputs[0]; + padding_left_index = inputs[1]; + padding_right_index = inputs[2]; + padding_top_index = inputs[3]; + padding_bottom_index = inputs[4]; + hstride_index = inputs[5]; + vstride_index = inputs[6]; + kw_index = inputs[7]; + kh_index = inputs[8]; + activation_index = inputs[9]; +} + +} // namespace Explicit + +namespace Implicit +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 7 && outputCount == 1); + + ofm_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> IFM Tensor Index + // 1 -> Padding Code (ANEURALNETWORKS_PADDING_SAME or ANEURALNETWORKS_PADDING_VALID) Index + // 2 -> Horizontal (over width) Stride Index + // 3 -> Vertial (over height) Stride Index + // 4 -> Filter Width Index + // 5 -> Filter Height Index + // 6 -> FuseCode (activation) Index + ifm_index = inputs[0]; + padding_index = inputs[1]; + hstride_index = inputs[2]; + vstride_index = inputs[3]; + kw_index = inputs[4]; + kh_index = inputs[5]; + activation_index = inputs[6]; +} + +} // namespace Implicit +} // namespace AvgPool2D +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/AvgPool2D.h b/runtime/contrib/pure_arm_compute/src/internal/op/AvgPool2D.h new file mode 100644 index 000000000..cf9061ca9 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/AvgPool2D.h @@ -0,0 +1,198 @@ +/* + * 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. + */ + +/** + * @file AvgPool2D.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines internal::tflite::op::AvgPool2D Param structs + * and internal::tflite::op::AvgPool2D Node classes + */ +#ifndef __INTERNAL_OP_AVG_POOL_2D_H__ +#define __INTERNAL_OP_AVG_POOL_2D_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace AvgPool2D +{ +namespace Explicit +{ + +/** + * @brief Struct to have indexes for operation parameter + */ +struct Param +{ + int32_t ofm_index; /**< Index of output feature map */ + + int32_t ifm_index; /**< Index of input feature map */ + + int32_t kw_index; /**< Index of kernel width */ + int32_t kh_index; /**< Index of kernel height */ + + int32_t hstride_index; /**< Index of horizontal stride */ + int32_t vstride_index; /**< Index of vertical stride */ + + int32_t padding_left_index; /**< Index of padding left */ + int32_t padding_right_index; /**< Index of padding right */ + int32_t padding_top_index; /**< Index of padding top */ + int32_t padding_bottom_index; /**< Index of padding bottom */ + + int32_t activation_index; /**< Index of activation */ + /** + * @brief Construct as default + */ + Param() = default; + /** + * @brief Construct a new Param object with params + * @param[in] inputCount Count of inputs + * @param[in] inputs Pointer of inputs + * @param[in] outputCount Count of outputs + * @param[in] outputs Pointer of outputs + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to represent an operation of data structure + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new Node object with param + * @param[in] param Param object that makes up a Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Destruct as default + */ + virtual ~Node() = default; + +public: + /** + * @brief Get a reference of Param object + * @return Reference of Param object + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Visit this Node by NodeVisitor + * @param[in] v Visitor + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace Explicit + +namespace Implicit +{ + +/** + * @brief Struct to have indexes for operation parameter + */ +struct Param +{ + int32_t ofm_index; /**< Index of output feature map */ + + int32_t ifm_index; /**< Index of input feature map */ + + int32_t kw_index; /**< Index of kernel width */ + int32_t kh_index; /**< Index of kernel height */ + + int32_t hstride_index; /**< Index of horizontal stride */ + int32_t vstride_index; /**< Index of vertical stride */ + + int32_t padding_index; /**< Index of padding */ + int32_t activation_index; /**< Index of activation */ + /** + * @brief Construct as default + */ + Param() = default; + /** + * @brief Construct a new Param object with params + * @param[in] inputCount Count of inputs + * @param[in] inputs Pointer of inputs + * @param[in] outputCount Count of outputs + * @param[in] outputs Pointer of outputs + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to represent an operation of data structure + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new Node object with param + * @param[in] param Param object that makes up a Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Destruct as default + */ + virtual ~Node() = default; + +public: + /** + * @brief Get a reference of Param object + * @return Reference of Param object + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Visit this Node by NodeVisitor + * @param[in] v Visitor + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace Implicit +} // namespace AvgPool2D +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_MAX_POOL_2D_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/BatchToSpaceNd.cc b/runtime/contrib/pure_arm_compute/src/internal/op/BatchToSpaceNd.cc new file mode 100644 index 000000000..0768039d0 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/BatchToSpaceNd.cc @@ -0,0 +1,63 @@ +/*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 "internal/op/BatchToSpaceNd.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace BatchToSpaceNd +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace BatchToSpaceNd +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace BatchToSpaceNd +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 2 && outputCount == 1); + + output_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> Input Tensor Index + // 1 -> Block size Index + input_index = inputs[0]; + block_size_index = inputs[1]; +} + +} // namespace BatchToSpaceNd +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/BatchToSpaceNd.h b/runtime/contrib/pure_arm_compute/src/internal/op/BatchToSpaceNd.h new file mode 100644 index 000000000..a514cb44c --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/BatchToSpaceNd.h @@ -0,0 +1,83 @@ +/* + * 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 __INTERNAL_OP_BATCHTOSPACE_ND_H__ +#define __INTERNAL_OP_BATCHTOSPACE_ND_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace BatchToSpaceNd +{ + +struct Param +{ + int32_t output_index; + + int32_t input_index; + int32_t block_size_index; + + Param() = default; + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +} // namespace BatchToSpaceNd +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace BatchToSpaceNd +{ +class Node final : public op::Node +{ +public: + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + virtual ~Node() = default; + +public: + const Param ¶m(void) const { return _param; } + +public: + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace BatchToSpaceNd +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_BATCHTOSPACE_Nd_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Cast.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Cast.cc new file mode 100644 index 000000000..13f58f137 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Cast.cc @@ -0,0 +1,62 @@ +/* + * 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 "internal/op/Cast.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Cast +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace Cast +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Cast +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 1 && outputCount == 1); + + output_index = outputs[0]; + + // Each input should be interpreted as follows: + // 0 -> input Tensor Index + input_index = inputs[0]; +} + +} // namespace Cast +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Cast.h b/runtime/contrib/pure_arm_compute/src/internal/op/Cast.h new file mode 100644 index 000000000..8af741a16 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Cast.h @@ -0,0 +1,108 @@ +/* + * 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. + */ + +/** + * @file Cast.h + * @brief This file contains accept function and params for Cast operation + * @ingroup COM_AI_RUNTIME + */ + +#ifndef __INTERNAL_OP_CAST_H__ +#define __INTERNAL_OP_CAST_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Cast +{ + +/** + * @brief Struct of Cast operation's param + */ +struct Param +{ + int32_t output_index; /**< Output index */ + + int32_t input_index; /**< Input index */ + + /** + * @brief Construct a new Param object for Cast as default + */ + Param() = default; + + /** + * @brief Construct a new Param object for Cast with params + * @param [in] inputCount The number of input + * @param [in] inputs Array containing inputs + * @param [in] outputCount The number of output + * @param [in] outputs Array containing outputs + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to define operation node for Cast + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new Node object for Cast with param + * @param [in] param Parameters for Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Destroy the Node object for Cast + */ + virtual ~Node() = default; + +public: + /** + * @brief Get parameters for Cast + * @return Parameters of Cast + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Function for accepting node for Cast + * @param [in] v Node visitor for invoking visit function of Cast + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace Cast +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_Cast_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Concat.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Concat.cc new file mode 100644 index 000000000..ee1730051 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Concat.cc @@ -0,0 +1,69 @@ +/* + * 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 "internal/op/Concat.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Concat +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace Concat +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Concat +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(outputCount == 1); + + ofm_index = outputs[0]; + + // When there are N + 1 inputs, each input should be interpreted as follows: + // + // [0, N) -> Input tensors + // N -> Axis + axis_index = inputs[inputCount - 1]; + + for (uint32_t n = 0; n < inputCount - 1; ++n) + { + ifm_indexes.emplace_back(inputs[n]); + } +} + +} // namespace Concat +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Concat.h b/runtime/contrib/pure_arm_compute/src/internal/op/Concat.h new file mode 100644 index 000000000..207f964fb --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Concat.h @@ -0,0 +1,109 @@ +/* + * 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. + */ + +/** + * @file Concat.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines Concat node + */ + +#ifndef __INTERNAL_OP_CONCAT_H__ +#define __INTERNAL_OP_CONCAT_H__ + +#include "internal/op/Node.h" + +#include <cstdint> +#include <vector> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Concat +{ + +/** + * @brief Struct to manipulate parameter for Concat operation + */ +struct Param +{ + int32_t ofm_index; //!< index for output + + std::vector<int32_t> ifm_indexes; //!< index for input + int32_t axis_index; //!< index for axis + + /** + * @brief Default Constructor + */ + Param() = default; + /** + * @brief Construct a new Param object + * @param[in] inputCount the number of inputs + * @param[in] inputs pointer for input data + * @param[in] outputCount the number of outputs + * @param[in] outputs pointer for input data + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to define Concat Operation + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new Concat Node object + * @param param Parameter for Concat Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Default Destructor + */ + virtual ~Node() = default; + +public: + /** + * @brief Get parameter + * @return Param reference + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Accept a NodeVisitor so that it can visit this node + * @param [in] v Visitor + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; //!< parameter for Concat node +}; + +} // namespace Concat +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_CONCAT_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Conv2D.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Conv2D.cc new file mode 100644 index 000000000..a24d14632 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Conv2D.cc @@ -0,0 +1,126 @@ +/* + * 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 "internal/op/Conv2D.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Conv2D +{ +namespace Explicit +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace Explicit + +namespace Implicit +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace Implicit +} // namespace Conv2D +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Conv2D +{ +namespace Explicit +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 10 && outputCount == 1); + + ofm_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // + // 0 -> IFM Tensor Index + // 1 -> Kernel Tensor Index + // 2 -> Bias Tensor Index + // 3 -> Padding_left index + // 4 -> Padding_right index + // 5 -> Padding_top index + // 6 -> Padding_bottom index + // 7 -> Stride (width) Index + // 8 -> Stride (height) INdex + // 9 -> Activation Index + ifm_index = inputs[0]; + ker_index = inputs[1]; + bias_index = inputs[2]; + padding_left_index = inputs[3]; + padding_right_index = inputs[4]; + padding_top_index = inputs[5]; + padding_bottom_index = inputs[6]; + hstride_index = inputs[7]; + vstride_index = inputs[8]; + activation_index = inputs[9]; +} + +} // namespace Explicit + +namespace Implicit +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 7 && outputCount == 1); + + ofm_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // + // 0 -> IFM Tensor Index + // 1 -> Kernel Tensor Index + // 2 -> Bias Tensor Index + // 3 -> Padding Code (ANEURALNETWORKS_PADDING_SAME or ANEURALNETWORKS_PADDING_VALID) Index + // 4 -> Stride (width) Index + // 5 -> Stride (height) INdex + // 6 -> Activation Index + ifm_index = inputs[0]; + ker_index = inputs[1]; + bias_index = inputs[2]; + padding_index = inputs[3]; + hstride_index = inputs[4]; + vstride_index = inputs[5]; + activation_index = inputs[6]; +} + +} // namespace Implicit +} // namespace Conv2D +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Conv2D.h b/runtime/contrib/pure_arm_compute/src/internal/op/Conv2D.h new file mode 100644 index 000000000..de46fbb9c --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Conv2D.h @@ -0,0 +1,200 @@ +/* + * 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. + */ + +/** + * @file Conv2D.h + * @brief This file contains accept function and params for Conv2D operation + * @ingroup COM_AI_RUNTIME + */ + +#ifndef __INTERNAL_OP_CONV_2D_H__ +#define __INTERNAL_OP_CONV_2D_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Conv2D +{ +namespace Explicit +{ + +/** + * @brief Struct of Conv2D(explicit) operation's param + */ +struct Param +{ + int32_t ofm_index; /**< Output format index */ + + int32_t ifm_index; /**< Input format index */ + int32_t ker_index; /**< Kernel index */ + int32_t bias_index; /**< Bias index */ + + int32_t hstride_index; /**< Horizontal stride index */ + int32_t vstride_index; /**< Vertical stride index */ + + int32_t padding_left_index; /**< Left padding index */ + int32_t padding_right_index; /**< Right padding index */ + int32_t padding_top_index; /**< Top padding index */ + int32_t padding_bottom_index; /**< Bottomd padding index */ + + int32_t activation_index; /**< Activation index */ + + /** + * @brief Construct a new Param object for Conv2D(explicit) as default + */ + Param() = default; + + /** + * @brief Construct a new Param object for Conv2D(explicit) with params + * @param [in] inputCount The number of input + * @param [in] inputs Array containing inputs + * @param [in] outputCount The number of output + * @param [in] outputs Array containing outputs + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to define operation node for Conv2D(explicit) + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new Node object for conv2D(explicit) with param + * @param [in] param Parameters for Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Destroy the Node object for conv2D(explicit) + */ + virtual ~Node() = default; + +public: + /** + * @brief Get parameters for conv2D(explicit) + * @return Parameters of conv2D(explicit) + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Function for accepting node for conv2D(explicit) + * @param [in] v Node visitor for invoking visit function of conv2D(explicit) + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace Explicit + +namespace Implicit +{ + +/** + * @brief Struct of Conv2D(implicit) operation's param + */ +struct Param +{ + int32_t ofm_index; /**< Output format index */ + + int32_t ifm_index; /**< Input format index */ + int32_t ker_index; /**< Kernel index */ + int32_t bias_index; /**< Bias index */ + + int32_t hstride_index; /**< Horizontal stride index */ + int32_t vstride_index; /**< Vertical stride index */ + + int32_t padding_index; /**< Padding index */ + int32_t activation_index; /**< Activation index */ + + /** + * @brief Construct a new Param object for Conv2D(implicit) as default + */ + Param() = default; + + /** + * @brief Construct a new Param object for Conv2D(implicit) with params + * @param [in] inputCount The number of input + * @param [in] inputs Array containing inputs + * @param [in] outputCount The number of output + * @param [in] outputs Array containing outputs + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to define operation node for Conv2D(implicit) + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new Node object for conv2D(implicit) with param + * @param [in] param Parameters for Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Destroy the Node object for conv2D(implicit) + */ + virtual ~Node() = default; + +public: + /** + * @brief Get parameters for conv2D(implicit) + * @return Parameters of conv2D(implicit) + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Function for accepting node for conv2D(implicit) + * @param [in] v Node visitor for invoking visit function of conv2D(implicit) + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace Implicit +} // namespace Conv2D +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_CONV_2D_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/DepthToSpace.cc b/runtime/contrib/pure_arm_compute/src/internal/op/DepthToSpace.cc new file mode 100644 index 000000000..db164a148 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/DepthToSpace.cc @@ -0,0 +1,65 @@ +/* + * 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 "internal/op/DepthToSpace.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace DepthToSpace +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace DepthToSpace +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace DepthToSpace +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 2 && outputCount == 1); + + output_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> Input Tensor Index + // 1 -> Block size Index + input_index = inputs[0]; + block_size_index = inputs[1]; +} + +} // namespace DepthToSpace +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/DepthToSpace.h b/runtime/contrib/pure_arm_compute/src/internal/op/DepthToSpace.h new file mode 100644 index 000000000..dd4c5c914 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/DepthToSpace.h @@ -0,0 +1,70 @@ +/* + * 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 __INTERNAL_OP_DEPTHTOSPACE_H__ +#define __INTERNAL_OP_DEPTHTOSPACE_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace DepthToSpace +{ + +struct Param +{ + int32_t output_index; + + int32_t input_index; + int32_t block_size_index; + + Param() = default; + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +class Node final : public op::Node +{ +public: + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + virtual ~Node() = default; + +public: + const Param ¶m(void) const { return _param; } + +public: + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace DepthToSpace +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_DEPTHTOSPACE_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/DepthwiseConv2D.cc b/runtime/contrib/pure_arm_compute/src/internal/op/DepthwiseConv2D.cc new file mode 100644 index 000000000..f4d1ca3c5 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/DepthwiseConv2D.cc @@ -0,0 +1,128 @@ +/* + * 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 "internal/op/DepthwiseConv2D.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace DepthwiseConv2D +{ +namespace Explicit +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace Explicit + +namespace Implicit +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace Implicit +} // namespace DepthwiseConv2D +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace DepthwiseConv2D +{ +namespace Explicit +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 11 && outputCount == 1); + + ofm_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> IFM Tensor Index + // 1 -> Kernel Tensor Index + // 2 -> Bias Tensor Index + // 3 -> Padding_left index + // 4 -> Padding_right index + // 5 -> Padding_top index + // 6 -> Padding_bottom index + // 7 -> Stride (width) Index + // 8 -> Stride (height) INdex + // 9 -> Depthwise Multiplier + // 10 -> Activation Index + ifm_index = inputs[0]; + ker_index = inputs[1]; + bias_index = inputs[2]; + padding_left_index = inputs[3]; + padding_right_index = inputs[4]; + padding_top_index = inputs[5]; + padding_bottom_index = inputs[6]; + hstride_index = inputs[7]; + vstride_index = inputs[8]; + multiplier_index = inputs[9]; + activation_index = inputs[10]; +} + +} // namespace Explicit + +namespace Implicit +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 8 && outputCount == 1); + + ofm_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> IFM Tensor Index + // 1 -> Kernel Tensor Index + // 2 -> Bias Tensor Index + // 3 -> Padding Code (ANEURALNETWORKS_PADDING_SAME or ANEURALNETWORKS_PADDING_VALID) Index + // 4 -> Stride (width) Index + // 5 -> Stride (height) INdex + // 6 -> Depthwise Multiplier + // 7 -> Activation Index + ifm_index = inputs[0]; + ker_index = inputs[1]; + bias_index = inputs[2]; + padding_index = inputs[3]; + hstride_index = inputs[4]; + vstride_index = inputs[5]; + multiplier_index = inputs[6]; + activation_index = inputs[7]; +} + +} // namespace Implicit +} // namespace DepthwiseConv2D +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/DepthwiseConv2D.h b/runtime/contrib/pure_arm_compute/src/internal/op/DepthwiseConv2D.h new file mode 100644 index 000000000..01a9e48be --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/DepthwiseConv2D.h @@ -0,0 +1,198 @@ +/* + * 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. + */ + +/** + * @file DepthwiseConv2D.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines internal::tflite::op::DepthwiseConv2D Param structs + * and internal::tflite::op::DepthwiseConv2D Node classes + */ +#ifndef __INTERNAL_OP_DEPTHWISE_CONV_2D_H__ +#define __INTERNAL_OP_DEPTHWISE_CONV_2D_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace DepthwiseConv2D +{ +namespace Explicit +{ + +/** + * @brief Struct to have indexes for explicit padding DepthwiseConv2D operation parameter + */ +struct Param +{ + int32_t ofm_index; /**< Index of output feature map */ + + int32_t ifm_index; /**< Index of input feature map */ + int32_t ker_index; /**< Index of kernel */ + int32_t bias_index; /**< Index of bias */ + + int32_t hstride_index; /**< Index of horizontal stride */ + int32_t vstride_index; /**< Index of vertical stride */ + + int32_t padding_left_index; /**< Index of padding left */ + int32_t padding_right_index; /**< Index of padding right */ + int32_t padding_top_index; /**< Index of padding top */ + int32_t padding_bottom_index; /**< Index of padding bottom */ + + int32_t multiplier_index; /**< Index of multipler */ + int32_t activation_index; /**< Index of activation */ + /** + * @brief Construct as default + */ + Param() = default; + /** + * @brief Construct a new Param object with params + * @param[in] inputCount Count of inputs + * @param[in] inputs Pointer of inputs + * @param[in] outputCount Count of outputs + * @param[in] outputs Pointer of outputs + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to represent an explicit padding DepthwiseConv2D operation of data structure + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new Node object with param + * @param[in] param Param object that makes up a Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Destruct as default + */ + virtual ~Node() = default; + +public: + /** + * @brief Get a reference of Param object + * @return Reference of Param object + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Visit this Node by NodeVisitor + * @param[in] v Visitor + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace Explicit + +/** + * @brief Struct to have indexes for implicit padding DepthwiseConv2D operation parameter + */ +namespace Implicit +{ + +struct Param +{ + int32_t ofm_index; /**< Index of output feature map */ + + int32_t ifm_index; /**< Index of input feature map */ + int32_t ker_index; /**< Index of kernel */ + int32_t bias_index; /**< Index of bias */ + + int32_t hstride_index; /**< Index of horizontal stride */ + int32_t vstride_index; /**< Index of vertical stride */ + + int32_t padding_index; /**< Index of padding */ + int32_t multiplier_index; /**< Index of multipler */ + int32_t activation_index; /**< Index of activation */ + /** + * @brief Construct as default + */ + Param() = default; + /** + * @brief Construct a new Param object with params + * @param[in] inputCount Count of inputs + * @param[in] inputs Pointer of inputs + * @param[in] outputCount Count of outputs + * @param[in] outputs Pointer of outputs + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to represent an implicit padding DepthwiseConv2D operation of data structure + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new Node object with param + * @param[in] param Param object that makes up a Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Destruct as default + */ + virtual ~Node() = default; + +public: + /** + * @brief Get a reference of Param object + * @return Reference of Param object + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Visit this Node by NodeVisitor + * @param[in] v Visitor + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace Implicit +} // namespace DepthwiseConv2D +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_CONV_2D_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Dequantize.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Dequantize.cc new file mode 100644 index 000000000..7062463a2 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Dequantize.cc @@ -0,0 +1,62 @@ +/* + * 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 "internal/op/Dequantize.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Dequantize +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace Dequantize +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Dequantize +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 1 && outputCount == 1); + + output_index = outputs[0]; + + // Each input should be interpreted as follows: + // 0 -> input Tensor Index + input_index = inputs[0]; +} + +} // namespace Dequantize +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Dequantize.h b/runtime/contrib/pure_arm_compute/src/internal/op/Dequantize.h new file mode 100644 index 000000000..f19898e9e --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Dequantize.h @@ -0,0 +1,106 @@ +/* + * 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. + */ + +/** + * @file Dequantize.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines internal::tflite::op::Dequantize::Param struct + * and internal::tflite::op::Dequantize::Node class + */ +#ifndef __INTERNAL_OP_DEQUANTIZE_H__ +#define __INTERNAL_OP_DEQUANTIZE_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Dequantize +{ + +/** + * @brief Struct to have indexes for Dequantize operation parameter + */ +struct Param +{ + int32_t output_index; /**< Index of output feature map */ + + int32_t input_index; /**< Index of input feature map */ + /** + * @brief Construct as default + */ + Param() = default; + /** + * @brief Construct a new Param object with params + * @param[in] inputCount Count of inputs + * @param[in] inputs Pointer of inputs + * @param[in] outputCount Count of outputs + * @param[in] outputs Pointer of outputs + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to represent an Dequantize operation of data structure + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new Node object with param + * @param[in] param Param object that makes up a Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Destruct as default + */ + virtual ~Node() = default; + +public: + /** + * @brief Get a reference of Param object + * @return Reference of Param object + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Visit this Node by NodeVisitor + * @param[in] v Visitor + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace Dequantize +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_DEQUANTIZE_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Div.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Div.cc new file mode 100644 index 000000000..649407eab --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Div.cc @@ -0,0 +1,67 @@ +/* + * 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 "internal/op/Div.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Div +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace Div +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Div +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 3 && outputCount == 1); + + ofm_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> LHS Tensor Index + // 1 -> RHS Tensor Index + // 2 -> Activation Index + lhs_index = inputs[0]; + rhs_index = inputs[1]; + activation_index = inputs[2]; +} + +} // namespace Div +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Div.h b/runtime/contrib/pure_arm_compute/src/internal/op/Div.h new file mode 100644 index 000000000..d5fc09d19 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Div.h @@ -0,0 +1,108 @@ +/* + * 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. + */ + +/** + * @file Div.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines internal::tflite::op::Div::Param struct + * and internal::tflite::op::Div::Node class + */ +#ifndef __INTERNAL_OP_DIV_H__ +#define __INTERNAL_OP_DIV_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Div +{ + +/** + * @brief Struct to have indexes for operation parameter + */ +struct Param +{ + int32_t ofm_index; /**< Index of output feature map */ + + int32_t lhs_index; /**< Index of lhs */ + int32_t rhs_index; /**< Index of rhs */ + int32_t activation_index; /**< Index of activation */ + /** + * @brief Construct as default + */ + Param() = default; + /** + * @brief Construct a new Param object with params + * @param[in] inputCount Count of inputs + * @param[in] inputs Pointer of inputs + * @param[in] outputCount Count of outputs + * @param[in] outputs Pointer of outputs + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to represent an operation of data structure + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new Node object with param + * @param[in] param Param object that makes up a Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Destruct as default + */ + virtual ~Node() = default; + +public: + /** + * @brief Get a reference of Param object + * @return Reference of Param object + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Visit this Node by NodeVisitor + * @param[in] v Visitor + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace Div +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_DIV_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/EmbeddingLookup.cc b/runtime/contrib/pure_arm_compute/src/internal/op/EmbeddingLookup.cc new file mode 100644 index 000000000..a6eda3473 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/EmbeddingLookup.cc @@ -0,0 +1,65 @@ +/* + * 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 "internal/op/EmbeddingLookup.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace EmbeddingLookup +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace EmbeddingLookup +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace EmbeddingLookup +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 2 && outputCount == 1); + + output_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> Lookups Index + // 1 -> Values Index + lookups_index = inputs[0]; + values_index = inputs[1]; +} + +} // namespace EmbeddingLookup +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/EmbeddingLookup.h b/runtime/contrib/pure_arm_compute/src/internal/op/EmbeddingLookup.h new file mode 100644 index 000000000..17e8485f7 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/EmbeddingLookup.h @@ -0,0 +1,109 @@ +/* + * 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. + */ + +/** + * @file EmbeddingLookup.h + * @brief This file contains accept function and params for EmbeddingLookup operation + * @ingroup COM_AI_RUNTIME + */ + +#ifndef __INTERNAL_OP_EMBEDDING_LOOKUP_H__ +#define __INTERNAL_OP_EMBEDDING_LOOKUP_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace EmbeddingLookup +{ + +/** + * @brief Struct of EmbeddingLookup operation's param + */ +struct Param +{ + int32_t output_index; /**< Output index */ + + int32_t lookups_index; /**< Lookups index */ + int32_t values_index; /**< Values index */ + + /** + * @brief Construct a new Param object for EmbeddingLookup as default + */ + Param() = default; + + /** + * @brief Construct a new Param object for EmbeddingLookup with params + * @param [in] inputCount The number of input + * @param [in] inputs Array containing inputs + * @param [in] outputCount The number of output + * @param [in] outputs Array containing outputs + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to define operation node for EmbeddingLookup + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new Node object for EmbeddingLookup with param + * @param [in] param Parameters for Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Destroy the Node object for EmbeddingLookup + */ + virtual ~Node() = default; + +public: + /** + * @brief Get parameters for EmbeddingLookup + * @return Parameters of EmbeddingLookup + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Function for accepting node for EmbeddingLookup + * @param [in] v Node visitor for invoking visit function of EmbeddingLookup + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace EmbeddingLookup +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_EMBEDDING_LOOKUP_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Equal.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Equal.cc new file mode 100644 index 000000000..b9cccc6a9 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Equal.cc @@ -0,0 +1,65 @@ +/* + * 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 "internal/op/Equal.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Equal +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace Equal +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Equal +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 2 && outputCount == 1); + + output_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> input1 Tensor Index + // 1 -> input2 Tensor Index + input1_index = inputs[0]; + input2_index = inputs[1]; +} + +} // namespace Equal +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Equal.h b/runtime/contrib/pure_arm_compute/src/internal/op/Equal.h new file mode 100644 index 000000000..78b9f846f --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Equal.h @@ -0,0 +1,83 @@ +/* + * 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 __INTERNAL_OP_EQUAL_H__ +#define __INTERNAL_OP_EQUAL_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Equal +{ + +struct Param +{ + int32_t output_index; + + int32_t input1_index; + int32_t input2_index; + + Param() = default; + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +} // namespace Equal +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Equal +{ +class Node final : public op::Node +{ +public: + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + virtual ~Node() = default; + +public: + const Param ¶m(void) const { return _param; } + +public: + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace Equal +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_EQUAL_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Exp.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Exp.cc new file mode 100644 index 000000000..6f1aa8f42 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Exp.cc @@ -0,0 +1,63 @@ +/* + * 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 "internal/op/Exp.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Exp +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace Exp +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Exp +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 1 && outputCount == 1); + + ofm_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> Input Tensor Index + ifm_index = inputs[0]; +} + +} // namespace Exp +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Exp.h b/runtime/contrib/pure_arm_compute/src/internal/op/Exp.h new file mode 100644 index 000000000..ac7f244b7 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Exp.h @@ -0,0 +1,69 @@ +/* + * 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 __INTERNAL_OP_EXP_H__ +#define __INTERNAL_OP_EXP_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Exp +{ + +struct Param +{ + int32_t ofm_index; + + int32_t ifm_index; + + Param() = default; + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +class Node final : public op::Node +{ +public: + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + virtual ~Node() = default; + +public: + const Param ¶m(void) const { return _param; } + +public: + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace Exp +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_EXP_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Floor.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Floor.cc new file mode 100644 index 000000000..c04f0c8ab --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Floor.cc @@ -0,0 +1,62 @@ +/* + * 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 "internal/op/Floor.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Floor +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace Floor +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Floor +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 1 && outputCount == 1); + + output_index = outputs[0]; + + // Each input should be interpreted as follows: + // 0 -> input Tensor Index + input_index = inputs[0]; +} + +} // namespace Floor +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Floor.h b/runtime/contrib/pure_arm_compute/src/internal/op/Floor.h new file mode 100644 index 000000000..5264ec10c --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Floor.h @@ -0,0 +1,108 @@ +/* + * 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. + */ + +/** + * @file Floor.h + * @brief This file contains accept function and params for Floor operation + * @ingroup COM_AI_RUNTIME + */ + +#ifndef __INTERNAL_OP_FLOOR_H__ +#define __INTERNAL_OP_FLOOR_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Floor +{ + +/** + * @brief Struct of Floor operation's param + */ +struct Param +{ + int32_t output_index; /**< Output index */ + + int32_t input_index; /**< Input index */ + + /** + * @brief Construct a new Param object for Floor as default + */ + Param() = default; + + /** + * @brief Construct a new Param object for Floor with params + * @param [in] inputCount The number of input + * @param [in] inputs Array containing inputs + * @param [in] outputCount The number of output + * @param [in] outputs Array containing outputs + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to define operation node for Floor + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new Node object for Floor with param + * @param [in] param Parameters for Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Destroy the Node object for Floor + */ + virtual ~Node() = default; + +public: + /** + * @brief Get parameters for Floor + * @return Parameters of Floor + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Function for accepting node for Floor + * @param [in] v Node visitor for invoking visit function of Floor + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace Floor +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_FLOOR_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/FullyConnected.cc b/runtime/contrib/pure_arm_compute/src/internal/op/FullyConnected.cc new file mode 100644 index 000000000..491fa5918 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/FullyConnected.cc @@ -0,0 +1,69 @@ +/* + * 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 "internal/op/FullyConnected.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace FullyConnected +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace FullyConnected +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace FullyConnected +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 4 && outputCount == 1); + + output_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> A tensor, specifying the input. + // 1 -> A 2-D tensor, specifying the weights + // 2 -> A 1-D tensor, specifying the bias + // 3 -> An INT32 value, and has to be one of the FuseCode values + input_index = inputs[0]; + weight_index = inputs[1]; + bias_index = inputs[2]; + activation_index = inputs[3]; +} + +} // namespace FullyConnected +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/FullyConnected.h b/runtime/contrib/pure_arm_compute/src/internal/op/FullyConnected.h new file mode 100644 index 000000000..434308435 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/FullyConnected.h @@ -0,0 +1,114 @@ +/* + * 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. + */ + +/** + * @file FullyConnected.h + * @brief This file contains accept function and params for FullyConnected operation + * @ingroup COM_AI_RUNTIME + */ + +#ifndef __INTERNAL_OP_FULLY_CONNTECTED_H__ +#define __INTERNAL_OP_FULLY_CONNTECTED_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace FullyConnected +{ + +/** + * @brief Struct of FullyConnected operation's param + */ +struct Param +{ + int32_t output_index; /**< Output index */ + + int32_t input_index; /**< Input index */ + int32_t weight_index; /**< Weight index */ + int32_t bias_index; /**< Bias index */ + int32_t activation_index; /**< Activation index */ + + /** + * @brief Construct a new Param object for FullyConnected as default + */ + Param() = default; + + /** + * @brief Construct a new Param object for FullyConnected with params + * @param [in] inputCount The number of input + * @param [in] inputs Array containing inputs + * @param [in] outputCount The number of output + * @param [in] outputs Array containing outputs + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to define operation node for FullyConnected + */ +class Node final : public op::Node +{ + /** + * @brief Construct a new Node object for FullyConnected with param + * @param [in] param Parameters for Node + */ +public: + /** + * @brief Destroy the Node object for FullyConnected + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Destroy the Node object for FullyConnected + */ + virtual ~Node() = default; + +public: + /** + * @brief Parameter Get parameters for FullyConnected + * @return _param Parameters of FullyConnected + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Function for accepting node for FullyConnected + * @param [in] v Node visitor for invoking visit function of FullyConnected + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace FullyConnected +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_FULLY_CONNTECTED_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Gather.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Gather.cc new file mode 100644 index 000000000..bc517d28c --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Gather.cc @@ -0,0 +1,67 @@ +/* + * 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 "internal/op/Gather.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Gather +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace Gather +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Gather +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 3 && outputCount == 1); + + ofm_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> input Tensor Index + // 1 -> indices Tensor Index + // 2 -> axis Index + ifm_index = inputs[0]; + indices_index = inputs[1]; + axis_index = inputs[2]; +} + +} // namespace Gather +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Gather.h b/runtime/contrib/pure_arm_compute/src/internal/op/Gather.h new file mode 100644 index 000000000..d40794f99 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Gather.h @@ -0,0 +1,109 @@ +/* + * 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. + */ + +/** + * @file Gather.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines Gather operation + */ + +#ifndef __INTERNAL_OP_GATHER_H__ +#define __INTERNAL_OP_GATHER_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Gather +{ + +/** + * @brief Struct to manipulate parameter for Gather operation + */ +struct Param +{ + int32_t ofm_index; //!< index for output feature map + + int32_t ifm_index; //!< index for ifm tensor + int32_t indices_index; //!< index for indices tensor + int32_t axis_index; //!< index for axis + + /** + * @brief Default Constructor + */ + Param() = default; + /** + * @brief Construct a new Param object + * @param[in] inputCount the number of inputs + * @param[in] inputs pointer for input data + * @param[in] outputCount the number of outputs + * @param[in] outputs pointer for input data + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to define Gather Operation + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new Tanh Node object + * @param param Parameter for Tanh Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Default Destructor + */ + virtual ~Node() = default; + +public: + /** + * @brief Get parameter + * @return Param reference + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Accept a NodeVisitor so that it can visit this node + * @param [in] v Visitor + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; //!< parameter for Gather node +}; + +} // namespace Gather +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_GATHER_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/HashtableLookup.cc b/runtime/contrib/pure_arm_compute/src/internal/op/HashtableLookup.cc new file mode 100644 index 000000000..7e04ecf82 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/HashtableLookup.cc @@ -0,0 +1,68 @@ +/* + * 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 "internal/op/HashtableLookup.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace HashtableLookup +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace HashtableLookup +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace HashtableLookup +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 3 && outputCount == 2); + + output_index = outputs[0]; + hits_index = outputs[1]; + + // Each input should be interpreted as follows: + // + // 0 -> Lookups Index + // 1 -> Keys Index + // 2 -> Values Index + lookups_index = inputs[0]; + keys_index = inputs[1]; + values_index = inputs[2]; +} + +} // namespace HashtableLookup +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/HashtableLookup.h b/runtime/contrib/pure_arm_compute/src/internal/op/HashtableLookup.h new file mode 100644 index 000000000..a5b43d1c7 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/HashtableLookup.h @@ -0,0 +1,109 @@ +/* + * 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. + */ + +/** + * @file HashtableLookup.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines internal::tflite::op::HashtableLookup::Param struct + * and internal::tflite::op::HashtableLookup::Node class + */ +#ifndef __INTERNAL_OP_HASHTABLE_LOOKUP_H__ +#define __INTERNAL_OP_HASHTABLE_LOOKUP_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace HashtableLookup +{ + +/** + * @brief Struct to have indexes for operation parameter + */ +struct Param +{ + int32_t output_index; /**< Index of output feature map */ + int32_t hits_index; /**< Index of hits */ + + int32_t lookups_index; /**< Index of lookups */ + int32_t values_index; /**< Index of values */ + int32_t keys_index; /**< Index of keys */ + /** + * @brief Construct as default + */ + Param() = default; + /** + * @brief Construct a new Param object with params + * @param[in] inputCount Count of inputs + * @param[in] inputs Pointer of inputs + * @param[in] outputCount Count of outputs + * @param[in] outputs Pointer of outputs + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to represent an operation of data structure + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new Node object with param + * @param[in] param Param object that makes up a Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Destruct as default + */ + virtual ~Node() = default; + +public: + /** + * @brief Get a reference of Param object + * @return Reference of Param object + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Visit this Node by NodeVisitor + * @param[in] v Visitor + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace HashtableLookup +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_HASHTABLE_LOOKUP_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/L2Normalization.cc b/runtime/contrib/pure_arm_compute/src/internal/op/L2Normalization.cc new file mode 100644 index 000000000..44a6ee63d --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/L2Normalization.cc @@ -0,0 +1,60 @@ +/* + * 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 "internal/op/L2Normalization.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace L2Normalization +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace L2Normalization +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace L2Normalization +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 1 && outputCount == 1); + + ofm_index = outputs[0]; + + ifm_index = inputs[0]; +} + +} // namespace L2Normalization +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/L2Normalization.h b/runtime/contrib/pure_arm_compute/src/internal/op/L2Normalization.h new file mode 100644 index 000000000..2e94fac11 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/L2Normalization.h @@ -0,0 +1,106 @@ +/* + * 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. + */ + +/** + * @file L2Normalization.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines internal::tflite::op::L2Normalization::Param struct + * and internal::tflite::op::L2Normalization::Node class + */ +#ifndef __INTERNAL_OP_L2_NORMALIZATION_H__ +#define __INTERNAL_OP_L2_NORMALIZATION_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace L2Normalization +{ + +/** + * @brief Struct to have indexes for L2Normalization operation parameter + */ +struct Param +{ + int32_t ofm_index; /**< Index of output feature map */ + + int32_t ifm_index; /**< Index of input feature map */ + /** + * @brief Construct as default + */ + Param() = default; + /** + * @brief Construct a new Param object with params + * @param[in] inputCount Count of inputs + * @param[in] inputs Pointer of inputs + * @param[in] outputCount Count of outputs + * @param[in] outputs Pointer of outputs + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to represent an L2Normalization operation of data structure + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new Node object with param + * @param[in] param Param object that makes up a Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Destruct as default + */ + virtual ~Node() = default; + +public: + /** + * @brief Get a reference of Param object + * @return Reference of Param object + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Visit this Node by NodeVisitor + * @param[in] v Visitor + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace L2Normalization +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_L2_NORMALIZATION_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/L2Pool2D.cc b/runtime/contrib/pure_arm_compute/src/internal/op/L2Pool2D.cc new file mode 100644 index 000000000..64041ab49 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/L2Pool2D.cc @@ -0,0 +1,124 @@ +/* + * 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 "internal/op/L2Pool2D.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace L2Pool2D +{ +namespace Explicit +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace Explicit + +namespace Implicit +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace Implicit +} // namespace L2Pool2D +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace L2Pool2D +{ +namespace Explicit +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 10 && outputCount == 1); + + ofm_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> IFM Tensor Index + // 1 -> Padding_left index + // 2 -> Padding_right index + // 3 -> Padding_top index + // 4 -> Padding_bottom index + // 5 -> Horizontal (over width) Stride Index + // 6 -> Vertial (over height) Stride Index + // 7 -> Filter Width Index + // 8 -> Filter Height Index + // 9 -> FuseCode (activation) Index + ifm_index = inputs[0]; + padding_left_index = inputs[1]; + padding_right_index = inputs[2]; + padding_top_index = inputs[3]; + padding_bottom_index = inputs[4]; + hstride_index = inputs[5]; + vstride_index = inputs[6]; + kw_index = inputs[7]; + kh_index = inputs[8]; + activation_index = inputs[9]; +} + +} // namespace Explicit + +namespace Implicit +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 7 && outputCount == 1); + + ofm_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> IFM Tensor Index + // 1 -> Padding Code (ANEURALNETWORKS_PADDING_SAME or ANEURALNETWORKS_PADDING_VALID) Index + // 2 -> Horizontal (over width) Stride Index + // 3 -> Vertial (over height) Stride Index + // 4 -> Filter Width Index + // 5 -> Filter Height Index + // 6 -> FuseCode (activation) Index + ifm_index = inputs[0]; + padding_index = inputs[1]; + hstride_index = inputs[2]; + vstride_index = inputs[3]; + kw_index = inputs[4]; + kh_index = inputs[5]; + activation_index = inputs[6]; +} + +} // namespace Implicit +} // namespace L2Pool2D +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/L2Pool2D.h b/runtime/contrib/pure_arm_compute/src/internal/op/L2Pool2D.h new file mode 100644 index 000000000..facb223c7 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/L2Pool2D.h @@ -0,0 +1,198 @@ +/* + * 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. + */ + +/** + * @file L2Pool2D.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines internal::tflite::op::L2Pool2D Param structs + * and internal::tflite::op::L2Pool2D Node classes + */ +#ifndef __INTERNAL_OP_L2_POOL_2D_H__ +#define __INTERNAL_OP_L2_POOL_2D_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace L2Pool2D +{ +namespace Explicit +{ + +/** + * @brief Struct to have indexes for operation parameter + */ +struct Param +{ + int32_t ofm_index; /**< Index of output feature map */ + + int32_t ifm_index; /**< Index of input feature map */ + + int32_t kw_index; /**< Index of kernel width */ + int32_t kh_index; /**< Index of kernel height */ + + int32_t hstride_index; /**< Index of horizontal stride */ + int32_t vstride_index; /**< Index of vertical stride */ + + int32_t padding_left_index; /**< Index of padding left */ + int32_t padding_right_index; /**< Index of padding right */ + int32_t padding_top_index; /**< Index of padding top */ + int32_t padding_bottom_index; /**< Index of padding bottom */ + + int32_t activation_index; /**< Index of activation */ + /** + * @brief Construct as default + */ + Param() = default; + /** + * @brief Construct a new Param object with params + * @param[in] inputCount Count of inputs + * @param[in] inputs Pointer of inputs + * @param[in] outputCount Count of outputs + * @param[in] outputs Pointer of outputs + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to represent an operation of data structure + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new Node object with param + * @param[in] param Param object that makes up a Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Destruct as default + */ + virtual ~Node() = default; + +public: + /** + * @brief Get a reference of Param object + * @return Reference of Param object + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Visit this Node by NodeVisitor + * @param[in] v Visitor + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace Explicit + +namespace Implicit +{ + +/** + * @brief Struct to have indexes for operation parameter + */ +struct Param +{ + int32_t ofm_index; /**< Index of output feature map */ + + int32_t ifm_index; /**< Index of input feature map */ + + int32_t kw_index; /**< Index of kernel width */ + int32_t kh_index; /**< Index of kernel height */ + + int32_t hstride_index; /**< Index of horizontal stride */ + int32_t vstride_index; /**< Index of vertical stride */ + + int32_t padding_index; /**< Index of padding */ + int32_t activation_index; /**< Index of activation */ + /** + * @brief Construct as default + */ + Param() = default; + /** + * @brief Construct a new Param object with params + * @param[in] inputCount Count of inputs + * @param[in] inputs Pointer of inputs + * @param[in] outputCount Count of outputs + * @param[in] outputs Pointer of outputs + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to represent an operation of data structure + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new Node object with param + * @param[in] param Param object that makes up a Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Destruct as default + */ + virtual ~Node() = default; + +public: + /** + * @brief Get a reference of Param object + * @return Reference of Param object + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Visit this Node by NodeVisitor + * @param[in] v Visitor + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace Implicit +} // namespace L2Pool2D +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_L2_POOL_2D_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/LocalResponseNormalization.cc b/runtime/contrib/pure_arm_compute/src/internal/op/LocalResponseNormalization.cc new file mode 100644 index 000000000..b7419d923 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/LocalResponseNormalization.cc @@ -0,0 +1,64 @@ +/* + * 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 "internal/op/LocalResponseNormalization.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace LocalResponseNormalization +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace LocalResponseNormalization +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace LocalResponseNormalization +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 5 && outputCount == 1); + + ofm_index = outputs[0]; + + ifm_index = inputs[0]; + radius_index = inputs[1]; + bias_index = inputs[2]; + alpha_index = inputs[3]; + beta_index = inputs[4]; +} + +} // namespace LocalResponseNormalization +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/LocalResponseNormalization.h b/runtime/contrib/pure_arm_compute/src/internal/op/LocalResponseNormalization.h new file mode 100644 index 000000000..29e0699ad --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/LocalResponseNormalization.h @@ -0,0 +1,73 @@ +/* + * 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 __INTERNAL_OP_LOCAL_RESPONSE_NORMALIZATION_H__ +#define __INTERNAL_OP_LOCAL_RESPONSE_NORMALIZATION_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace LocalResponseNormalization +{ + +struct Param +{ + int32_t ofm_index; + + int32_t ifm_index; + int32_t radius_index; + int32_t bias_index; + int32_t alpha_index; + int32_t beta_index; + + Param() = default; + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +class Node final : public op::Node +{ +public: + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + virtual ~Node() = default; + +public: + const Param ¶m(void) const { return _param; } + +public: + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace LocalResponseNormalization +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_LOCAL_RESPONSE_NORMALIZATION_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/LogicalAnd.cc b/runtime/contrib/pure_arm_compute/src/internal/op/LogicalAnd.cc new file mode 100644 index 000000000..5b7da4d3b --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/LogicalAnd.cc @@ -0,0 +1,65 @@ +/* + * 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 "internal/op/LogicalAnd.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace LogicalAnd +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace LogicalAnd +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace LogicalAnd +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 2 && outputCount == 1); + + output_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> input1 Tensor Index + // 1 -> input2 Tensor Index + input1_index = inputs[0]; + input2_index = inputs[1]; +} + +} // namespace LogicalAnd +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/LogicalAnd.h b/runtime/contrib/pure_arm_compute/src/internal/op/LogicalAnd.h new file mode 100644 index 000000000..2f53f756d --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/LogicalAnd.h @@ -0,0 +1,83 @@ +/* + * 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 __INTERNAL_OP_LOGICAL_AND_H__ +#define __INTERNAL_OP_LOGICAL_AND_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace LogicalAnd +{ + +struct Param +{ + int32_t output_index; + + int32_t input1_index; + int32_t input2_index; + + Param() = default; + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +} // namespace LogicalAnd +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace LogicalAnd +{ +class Node final : public op::Node +{ +public: + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + virtual ~Node() = default; + +public: + const Param ¶m(void) const { return _param; } + +public: + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace LogicalAnd +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_LOGICAL_AND_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/LogicalNot.cc b/runtime/contrib/pure_arm_compute/src/internal/op/LogicalNot.cc new file mode 100644 index 000000000..4cb6a8e2a --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/LogicalNot.cc @@ -0,0 +1,60 @@ +/* + * 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 "internal/op/LogicalNot.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace LogicalNot +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace LogicalNot +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace LogicalNot +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 1 && outputCount == 1); + + output_index = outputs[0]; + + input_index = inputs[0]; +} + +} // namespace LogicalNot +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/LogicalNot.h b/runtime/contrib/pure_arm_compute/src/internal/op/LogicalNot.h new file mode 100644 index 000000000..9593deafe --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/LogicalNot.h @@ -0,0 +1,82 @@ +/* + * 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 __INTERNAL_OP_LOGICAL_NOT_H__ +#define __INTERNAL_OP_LOGICAL_NOT_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace LogicalNot +{ + +struct Param +{ + int32_t output_index; + + int32_t input_index; + + Param() = default; + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +} // namespace LogicalNot +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace LogicalNot +{ +class Node final : public op::Node +{ +public: + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + virtual ~Node() = default; + +public: + const Param ¶m(void) const { return _param; } + +public: + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace LogicalNot +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_LOGICAL_NOT_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/LogicalOr.cc b/runtime/contrib/pure_arm_compute/src/internal/op/LogicalOr.cc new file mode 100644 index 000000000..8295f6f0b --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/LogicalOr.cc @@ -0,0 +1,65 @@ +/* + * 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 "internal/op/LogicalOr.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace LogicalOr +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace LogicalOr +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace LogicalOr +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 2 && outputCount == 1); + + output_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> input1 Tensor Index + // 1 -> input2 Tensor Index + input1_index = inputs[0]; + input2_index = inputs[1]; +} + +} // namespace LogicalOr +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/LogicalOr.h b/runtime/contrib/pure_arm_compute/src/internal/op/LogicalOr.h new file mode 100644 index 000000000..6487fa720 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/LogicalOr.h @@ -0,0 +1,83 @@ +/* + * 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 __INTERNAL_OP_LOGICAL_OR_H__ +#define __INTERNAL_OP_LOGICAL_OR_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace LogicalOr +{ + +struct Param +{ + int32_t output_index; + + int32_t input1_index; + int32_t input2_index; + + Param() = default; + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +} // namespace LogicalOr +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace LogicalOr +{ +class Node final : public op::Node +{ +public: + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + virtual ~Node() = default; + +public: + const Param ¶m(void) const { return _param; } + +public: + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace LogicalOr +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_LOGICAL_OR_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Logistic.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Logistic.cc new file mode 100644 index 000000000..93ecd043c --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Logistic.cc @@ -0,0 +1,63 @@ +/* + * 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 "internal/op/Logistic.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Logistic +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace Logistic +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Logistic +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 1 && outputCount == 1); + + ofm_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> Input Tensor Index + ifm_index = inputs[0]; +} + +} // namespace Logistic +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Logistic.h b/runtime/contrib/pure_arm_compute/src/internal/op/Logistic.h new file mode 100644 index 000000000..a42fdc0d4 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Logistic.h @@ -0,0 +1,105 @@ +/* + * 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. + */ + +/** + * @file Logistic.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines internal::tflite::op::Logistic::Param struct + * and internal::tflite::op::Logistic::Node class + */ +#ifndef __INTERNAL_OP_LOGISTIC_H__ +#define __INTERNAL_OP_LOGISTIC_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Logistic +{ + +/** + * @brief Struct to have indexes for operation parameter + */ +struct Param +{ + int32_t ofm_index; /**< Index of output feature map */ + + int32_t ifm_index; /**< Index of input feature map */ + /** + * @brief Construct as default + */ + Param() = default; + /** + * @brief Construct a new Param object with params + * @param[in] inputCount Count of inputs + * @param[in] inputs Pointer of inputs + * @param[in] outputCount Count of outputs + * @param[in] outputs Pointer of outputs + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to represent an operation of data structure + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new Node object with param + * @param[in] param Param object that makes up a Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Destruct as default + */ + virtual ~Node() = default; + +public: + /** + * @brief Get a reference of Param object + * @return Reference of Param object + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Visit this Node by NodeVisitor + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace Logistic +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_LOGISTIC_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Lstm.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Lstm.cc new file mode 100644 index 000000000..3f5e9a490 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Lstm.cc @@ -0,0 +1,85 @@ +/* + * 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 "internal/op/Lstm.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace LSTM +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace LSTM +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace LSTM +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 23 && outputCount == 4); + + scratch_buffer_index = outputs[0]; + output_state_out_index = outputs[1]; + cell_state_out_index = outputs[2]; + output_index = outputs[3]; + + input_index = inputs[0]; + input_to_input_weights_index = inputs[1]; + input_to_forget_weights_index = inputs[2]; + input_to_cell_weights_index = inputs[3]; + input_to_output_weights_index = inputs[4]; + recurrent_to_input_weights_index = inputs[5]; + recurrent_to_forget_weights_index = inputs[6]; + recurrent_to_cell_weights_index = inputs[7]; + recurrent_to_output_weights_index = inputs[8]; + cell_to_input_weights_index = inputs[9]; + cell_to_forget_weights_index = inputs[10]; + cell_to_output_weights_index = inputs[11]; + input_gate_bias_index = inputs[12]; + forget_gate_bias_index = inputs[13]; + cell_bias_index = inputs[14]; + output_gate_bias_index = inputs[15]; + projection_weights_index = inputs[16]; + projection_bias_index = inputs[17]; + output_state_in_index = inputs[18]; + cell_state_in_index = inputs[19]; + activation_index = inputs[20]; + cell_threshold_index = inputs[21]; + projection_threshold_index = inputs[22]; +} + +} // namespace LSTM +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Lstm.h b/runtime/contrib/pure_arm_compute/src/internal/op/Lstm.h new file mode 100644 index 000000000..f51f0402a --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Lstm.h @@ -0,0 +1,131 @@ +/* + * 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. + */ + +/** + * @file Lstm.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines internal::tflite::op::LSTM::Param struct + * and internal::tflite::op::LSTM::Node class + */ +#ifndef __INTERNAL_OP_LSTM_H__ +#define __INTERNAL_OP_LSTM_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace LSTM +{ + +/** + * @brief Struct to have indexes for operation parameter + */ +struct Param +{ + int32_t scratch_buffer_index; /**< Index of scartch buffer */ + int32_t output_state_out_index; /**< Index of output state out */ + int32_t cell_state_out_index; /**< Index of cell state out */ + int32_t output_index; /**< Index of output */ + + int32_t input_index; /**< Index of input */ + int32_t input_to_input_weights_index; /**< Index of input to input weights */ + int32_t input_to_forget_weights_index; /**< Index of input to forget weights */ + int32_t input_to_cell_weights_index; /**< Index of input to cell weights */ + int32_t input_to_output_weights_index; /**< Index of input to output weights */ + int32_t recurrent_to_input_weights_index; /**< Index of recurrent to input weights */ + int32_t recurrent_to_forget_weights_index; /**< Index of recurrent to forget weights */ + int32_t recurrent_to_cell_weights_index; /**< Index of recurrent to cell weights */ + int32_t recurrent_to_output_weights_index; /**< Index of recurrent to output weights */ + int32_t cell_to_input_weights_index; /**< Index of cell to input weights */ + int32_t cell_to_forget_weights_index; /**< Index of cell to forget weights */ + int32_t cell_to_output_weights_index; /**< Index of cell to output weights */ + int32_t input_gate_bias_index; /**< Index of input gate bias */ + int32_t forget_gate_bias_index; /**< Index of forget gate bias */ + int32_t cell_bias_index; /**< Index of cell bias */ + int32_t output_gate_bias_index; /**< Index of output gate bias */ + int32_t projection_weights_index; /**< Index of projection weights */ + int32_t projection_bias_index; /**< Index of projection bias */ + int32_t output_state_in_index; /**< Index of output state in */ + int32_t cell_state_in_index; /**< Index of cell state in */ + int32_t activation_index; /**< Index of activation */ + int32_t cell_threshold_index; /**< Index of cell threshold */ + int32_t projection_threshold_index; /**< Index of projection threshold */ + + /** + * @brief Construct as default + */ + Param() = default; + /** + * @brief Construct a new Param object with params + * @param[in] inputCount Count of inputs + * @param[in] inputs Pointer of inputs + * @param[in] outputCount Count of outputs + * @param[in] outputs Pointer of outputs + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to represent an operation of data structure + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new Node object with param + * @param[in] param Param object that makes up a Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Destruct as default + */ + virtual ~Node() = default; + +public: + /** + * @brief Get a reference of Param object + * @return Reference of Param object + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Visit this Node by NodeVisitor + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace LSTM +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_LSTM_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/MaxPool2D.cc b/runtime/contrib/pure_arm_compute/src/internal/op/MaxPool2D.cc new file mode 100644 index 000000000..0c80f1f5c --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/MaxPool2D.cc @@ -0,0 +1,124 @@ +/* + * 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 "internal/op/MaxPool2D.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace MaxPool2D +{ +namespace Explicit +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace Explicit + +namespace Implicit +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace Implicit +} // namespace MaxPool2D +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace MaxPool2D +{ +namespace Explicit +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 10 && outputCount == 1); + + ofm_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> IFM Tensor Index + // 1 -> Padding_left index + // 2 -> Padding_right index + // 3 -> Padding_top index + // 4 -> Padding_bottom index + // 5 -> Horizontal (over width) Stride Index + // 6 -> Vertial (over height) Stride Index + // 7 -> Filter Width Index + // 8 -> Filter Height Index + // 9 -> FuseCode (activation) Index + ifm_index = inputs[0]; + padding_left_index = inputs[1]; + padding_right_index = inputs[2]; + padding_top_index = inputs[3]; + padding_bottom_index = inputs[4]; + hstride_index = inputs[5]; + vstride_index = inputs[6]; + kw_index = inputs[7]; + kh_index = inputs[8]; + activation_index = inputs[9]; +} + +} // namespace Explicit + +namespace Implicit +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 7 && outputCount == 1); + + ofm_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> IFM Tensor Index + // 1 -> Padding Code (ANEURALNETWORKS_PADDING_SAME or ANEURALNETWORKS_PADDING_VALID) Index + // 2 -> Horizontal (over width) Stride Index + // 3 -> Vertial (over height) Stride Index + // 4 -> Filter Width Index + // 5 -> Filter Height Index + // 6 -> FuseCode (activation) Index + ifm_index = inputs[0]; + padding_index = inputs[1]; + hstride_index = inputs[2]; + vstride_index = inputs[3]; + kw_index = inputs[4]; + kh_index = inputs[5]; + activation_index = inputs[6]; +} + +} // namespace Implicit +} // namespace MaxPool2D +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/MaxPool2D.h b/runtime/contrib/pure_arm_compute/src/internal/op/MaxPool2D.h new file mode 100644 index 000000000..329ccecb7 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/MaxPool2D.h @@ -0,0 +1,202 @@ +/* + * 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. + */ + +/** + * @file MaxPool2D.h + * @brief This file contains accept function and params for MaxPool2D operation + * @ingroup COM_AI_RUNTIME + */ + +#ifndef __INTERNAL_OP_MAX_POOL_2D_H__ +#define __INTERNAL_OP_MAX_POOL_2D_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace MaxPool2D +{ +namespace Explicit +{ + +/** + * @brief Struct of MaxPool2D(Explicit) operation's param + */ +struct Param +{ + int32_t ofm_index; /**< Output format index */ + + int32_t ifm_index; /**< Input format index */ + + int32_t kw_index; /**< Kernel width index */ + int32_t kh_index; /**< Kernel height index */ + + int32_t hstride_index; /**< Horizontal stride index */ + int32_t vstride_index; /**< Vertical stride index */ + + int32_t padding_left_index; /**< Left padding index */ + int32_t padding_right_index; /**< Right padding index */ + int32_t padding_top_index; /**< Top padding index */ + int32_t padding_bottom_index; /**< Bottom padding index */ + + int32_t activation_index; /**< Activation index */ + + /** + * @brief Construct a new Param object for MaxPool2D(Explicit) as default + */ + Param() = default; + + /** + * @brief Construct a new Param object for MaxPool2D(Explicit) with params + * @param [in] inputCount The number of input + * @param [in] inputs Array containing inputs + * @param [in] outputCount The number of output + * @param [in] outputs Array containing outputs + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to define operation node for MaxPool2D(Explicit) + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new Node object for MaxPool2D(Explicit) with param + * @param [in] param Parameters for Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Destroy the Node object for MaxPool2D(Explicit) + */ + virtual ~Node() = default; + +public: + /** + * @brief Get parameters for MaxPool2D(Explicit) + * @return Parameters of MaxPool2D(Explicit) + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Function for accepting node for MaxPool2D(Explicit) + * @param [in] v Node visitor for invoking visit function of MaxPool2D(Explicit) + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace Explicit + +namespace Implicit +{ + +/** + * @brief Struct of MaxPool2D(Implicit) operation's param + */ +struct Param +{ + int32_t ofm_index; /**< Output format index */ + + int32_t ifm_index; /**< Input format index */ + + int32_t kw_index; /**< Kernel width index */ + int32_t kh_index; /**< Kernel height index */ + + int32_t hstride_index; /**< Horizontal stride index */ + int32_t vstride_index; /**< Vertical stride index */ + + int32_t padding_index; /**< Padding index */ + int32_t activation_index; /**< Activation index */ + + /** + * @brief Construct a new Param object for MaxPool2D(Implicit) as default + */ + Param() = default; + + /** + * @brief Construct a new Param object for MaxPool2D(Implicit) with params + * @param [in] inputCount The number of input + * @param [in] inputs Array containing inputs + * @param [in] outputCount The number of output + * @param [in] outputs Array containing outputs + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to define operation node for MaxPool2D(Implicit) + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new Node object for MaxPool2D(Implicit) with param + * @param [in] param Parameters for Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Destroy the Node object for MaxPool2D(Implicit) + */ + virtual ~Node() = default; + +public: + /** + * @brief Get parameters for MaxPool2D(Implicit) + * @return Parameters of MaxPool2D(Implicit) + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Function for accepting node for MaxPool2D(Implicit) + * @param [in] v Node visitor for invoking visit function of MaxPool2D(Implicit) + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace Implicit +} // namespace MaxPool2D +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_MAX_POOL_2D_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Mean.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Mean.cc new file mode 100644 index 000000000..222a3ee4a --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Mean.cc @@ -0,0 +1,67 @@ +/* + * 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 "internal/op/Mean.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Mean +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace Mean +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Mean +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 3 && outputCount == 1); + + ofm_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> ifm Tensor Index + // 1 -> axis Tensor Index + // 2 -> keep_dims Index + ifm_index = inputs[0]; + axis_index = inputs[1]; + keep_dims_index = inputs[2]; +} + +} // namespace Mean +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Mean.h b/runtime/contrib/pure_arm_compute/src/internal/op/Mean.h new file mode 100644 index 000000000..f8e7ed308 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Mean.h @@ -0,0 +1,108 @@ +/* + * 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. + */ + +/** + * @file Mean.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines internal::tflite::op::Mean::Param struct + * and internal::tflite::op::Mean::Node class + */ +#ifndef __INTERNAL_OP_MEAN_H__ +#define __INTERNAL_OP_MEAN_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Mean +{ + +/** + * @brief Struct to have indexes for operation parameter + */ +struct Param +{ + int32_t ofm_index; /**< Index of output feature map */ // output + + int32_t ifm_index; /**< Index of input feature map */ // input + int32_t axis_index; /**< Index of axis */ // axis + int32_t keep_dims_index; /**< Index of keep dims */ // keep_dims + /** + * @brief Construct as default + */ + Param() = default; + /** + * @brief Construct a new Param object with params + * @param[in] inputCount Count of inputs + * @param[in] inputs Pointer of inputs + * @param[in] outputCount Count of outputs + * @param[in] outputs Pointer of outputs + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to represent an operation of data structure + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new Node object with param + * @param[in] param Param object that makes up a Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Destruct as default + */ + virtual ~Node() = default; + +public: + /** + * @brief Get a reference of Param object + * @return Reference of Param object + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Visit this Node by NodeVisitor + * @param[in] v Visitor + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace Mean +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_MEAN_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Mul.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Mul.cc new file mode 100644 index 000000000..2a2ae00ed --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Mul.cc @@ -0,0 +1,67 @@ +/* + * 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 "internal/op/Mul.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Mul +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace Mul +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Mul +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 3 && outputCount == 1); + + ofm_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> LHS Tensor Index + // 1 -> RHS Tensor Index + // 2 -> Activation Index + lhs_index = inputs[0]; + rhs_index = inputs[1]; + activation_index = inputs[2]; +} + +} // namespace Mul +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Mul.h b/runtime/contrib/pure_arm_compute/src/internal/op/Mul.h new file mode 100644 index 000000000..9710dd057 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Mul.h @@ -0,0 +1,106 @@ +/* + * 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. + */ + +/** + * @file Mul.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines internal::tflite::op::Mul class + */ +#ifndef __INTERNAL_OP_MUL_H__ +#define __INTERNAL_OP_MUL_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Mul +{ + +/** + * @brief Struct to have indexes for operation parameter + */ +struct Param +{ + int32_t ofm_index; /** Index of output feature map */ + + int32_t lhs_index; /** Index of lhs */ + int32_t rhs_index; /** Index of rhs */ + int32_t activation_index; /** Index of activation */ + /** + * @brief Construct as default + */ + Param() = default; + /** + * @brief Construct a new Param object with params + * @param[in] inputCount Count of inputs + * @param[in] inputs Pointer of inputs + * @param[in] outputCount Count of outputs + * @param[in] outputs Pointer of outputs + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to represent an operation of data structure + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new Node object with param + * @param[in] param Param object that makes up a Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Destruct as default + */ + virtual ~Node() = default; + +public: + /** + * @brief Get a reference of Param object + * @return Reference of Param object + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Visit this Node by NodeVisitor + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace Mul +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_MUL_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Neg.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Neg.cc new file mode 100644 index 000000000..72fecf484 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Neg.cc @@ -0,0 +1,63 @@ +/* + * 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 "internal/op/Neg.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Neg +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace Neg +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Neg +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 1 && outputCount == 1); + + ofm_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> Input Tensor Index + ifm_index = inputs[0]; +} + +} // namespace Neg +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Neg.h b/runtime/contrib/pure_arm_compute/src/internal/op/Neg.h new file mode 100644 index 000000000..77507df3d --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Neg.h @@ -0,0 +1,69 @@ +/* + * 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 __INTERNAL_OP_NEG_H__ +#define __INTERNAL_OP_NEG_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Neg +{ + +struct Param +{ + int32_t ofm_index; + + int32_t ifm_index; + + Param() = default; + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +class Node final : public op::Node +{ +public: + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + virtual ~Node() = default; + +public: + const Param ¶m(void) const { return _param; } + +public: + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace Neg +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_NEG_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Node.h b/runtime/contrib/pure_arm_compute/src/internal/op/Node.h new file mode 100644 index 000000000..be1cbdb5b --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Node.h @@ -0,0 +1,60 @@ +/* + * 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. + */ + +/** + * @file Node.h + * @brief This file contains struct of Node and NodeVisitor + * @ingroup COM_AI_RUNTIME + */ + +#ifndef __INTERNAL_OP_NODE_H__ +#define __INTERNAL_OP_NODE_H__ + +namespace internal +{ +namespace tflite +{ +namespace op +{ + +/** + * @brief Struct of operation NodeVisitor + */ +struct NodeVisitor; + +/** + * @brief Struct of operation Node + */ +struct Node +{ + /** + * @brief Destroy the Node object for operation + */ + virtual ~Node() = default; + + /** + * @brief Function for accepting node for operation + * @param [in] v Node visitor for invoking visit function of operation + * @return N/A + */ + virtual void accept(NodeVisitor &&) const = 0; +}; + +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_NODE_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/NodeVisitor.h b/runtime/contrib/pure_arm_compute/src/internal/op/NodeVisitor.h new file mode 100644 index 000000000..0c1a4001d --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/NodeVisitor.h @@ -0,0 +1,493 @@ +/* + * 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. + */ + +/** + * @file NodeVisitor.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines NodeVisitor + */ + +#ifndef __INTERNAL_OP_NODE_VISITOR_H__ +#define __INTERNAL_OP_NODE_VISITOR_H__ + +#include "internal/op/Add.h" +#include "internal/op/Sub.h" +#include "internal/op/Mul.h" +#include "internal/op/Div.h" +#include "internal/op/Conv2D.h" +#include "internal/op/DepthwiseConv2D.h" +#include "internal/op/Dequantize.h" +#include "internal/op/MaxPool2D.h" +#include "internal/op/AvgPool2D.h" +#include "internal/op/ArgMax.h" +#include "internal/op/Concat.h" +#include "internal/op/Reshape.h" +#include "internal/op/ResizeBilinear.h" +#include "internal/op/StridedSlice.h" +#include "internal/op/FullyConnected.h" +#include "internal/op/Softmax.h" +#include "internal/op/ReduceMax.h" +#include "internal/op/ReduceMin.h" +#include "internal/op/Cast.h" +#include "internal/op/TopKV2.h" +#include "internal/op/Gather.h" +#include "internal/op/PReLU.h" +#include "internal/op/ReLU.h" +#include "internal/op/ReLU1.h" +#include "internal/op/ReLU6.h" +#include "internal/op/Tanh.h" +#include "internal/op/Squeeze.h" +#include "internal/op/Logistic.h" +#include "internal/op/Mean.h" +#include "internal/op/Rnn.h" +#include "internal/op/Transpose.h" +#include "internal/op/Lstm.h" +#include "internal/op/Floor.h" +#include "internal/op/Split.h" +#include "internal/op/RSQRT.h" +#include "internal/op/SQRT.h" +#include "internal/op/Pad.h" +#include "internal/op/SpaceToDepth.h" +#include "internal/op/SpaceToBatchND.h" +#include "internal/op/L2Pool2D.h" +#include "internal/op/EmbeddingLookup.h" +#include "internal/op/HashtableLookup.h" +#include "internal/op/L2Normalization.h" +#include "internal/op/SquaredDifference.h" +#include "internal/op/LocalResponseNormalization.h" +#include "internal/op/DepthToSpace.h" +#include "internal/op/Unpack.h" +#include "internal/op/Neg.h" +#include "internal/op/Exp.h" +#include "internal/op/ReduceSum.h" +#include "internal/op/Equal.h" +#include "internal/op/BatchToSpaceNd.h" +#include "internal/op/TransposeConv.h" +#include "internal/op/Pack.h" +#include "internal/op/Abs.h" +#include "internal/op/NotEqual.h" +#include "internal/op/LogicalAnd.h" +#include "internal/op/LogicalNot.h" +#include "internal/op/LogicalOr.h" + +namespace internal +{ +namespace tflite +{ +namespace op +{ + +/** + * @brief Struct to define visitor for operation Nodes + */ +struct NodeVisitor +{ + /** + * @brief Destruct NodeVisitor object with default + */ + virtual ~NodeVisitor() = default; + + /** + * @brief Visit an Add node + * @param[in] node Add node to visit + * @return N/A + */ + virtual void visit(const Add::Node &) = 0; + /** + * @brief Visit a Mul node + * @param[in] node Mul node to visit + * @return N/A + */ + virtual void visit(const Sub::Node &) = 0; + /** + * @brief Visit a Mul node + * @param[in] node Mul node to visit + * @return N/A + */ + virtual void visit(const Mul::Node &) = 0; + /** + * @brief Visit a Div node + * @param[in] node Div node to visit + * @return N/A + */ + virtual void visit(const Div::Node &) = 0; + /** + * @brief Visit a Conv2D node with implicit padding + * @param[in] node Conv2D node to visit + * @return N/A + */ + virtual void visit(const Conv2D::Implicit::Node &) = 0; + /** + * @brief Visit a Conv2D node with explicit padding + * @param[in] node Conv2D node to visit + * @return N/A + */ + virtual void visit(const Conv2D::Explicit::Node &) = 0; + /** + * @brief Visit a DepthwiseConv2D node with implicit padding + * @param[in] node DepthwiseConv2D node to visit + * @return N/A + */ + virtual void visit(const DepthwiseConv2D::Implicit::Node &) = 0; + /** + * @brief Visit a DepthwiseConv2D node with explicit padding + * @param[in] node DepthwiseConv2D node to visit + * @return N/A + */ + virtual void visit(const DepthwiseConv2D::Explicit::Node &) = 0; + /** + * @brief Visit a Dequantize node + * @param[in] node Dequantize node to visit + * @return N/A + */ + virtual void visit(const Dequantize::Node &) = 0; + /** + * @brief Visit a MaxPool2D node with implicit padding + * @param[in] node MaxPool2D node to visit + * @return N/A + */ + virtual void visit(const MaxPool2D::Implicit::Node &) = 0; + /** + * @brief Visit a MaxPool2D node with explicit padding + * @param[in] node MaxPool2D node to visit + * @return N/A + */ + virtual void visit(const MaxPool2D::Explicit::Node &) = 0; + /** + * @brief Visit an AvgPool2D node with implicit padding + * @param[in] node AvgPool2D node to visit + * @return N/A + */ + virtual void visit(const AvgPool2D::Implicit::Node &) = 0; + /** + * @brief Visit an AvgPool2D node with explicit padding + * @param[in] node AvgPool2D node to visit + * @return N/A + */ + virtual void visit(const AvgPool2D::Explicit::Node &) = 0; + /** + * @brief Visit a Concat node + * @param[in] node Concat node to visit + * @return N/A + */ + virtual void visit(const Concat::Node &) = 0; + /** + * @brief Visit a ArgMax node + * @param[in] node ArgMax node to visit + * @return N/A + */ + virtual void visit(const ArgMax::Node &) = 0; + /** + * @brief Visit an Reshape node + * @param[in] node Reshape node to visit + * @return N/A + */ + virtual void visit(const Reshape::Node &) = 0; + /** + * @brief Visit an ResizeBilinear node + * @param[in] node ResizeBilinear node to visit + * @return N/A + */ + virtual void visit(const ResizeBilinear::Node &) = 0; + /** + * @brief Visit a StridedSlice node + * @param[in] node StridedSlice node to visit + * @return N/A + */ + virtual void visit(const StridedSlice::Node &) = 0; + /** + * @brief Visit a FullyConnected node + * @param[in] node FullyConnected node to visit + * @return N/A + */ + virtual void visit(const FullyConnected::Node &) = 0; + /** + * @brief Visit a Softmax node + * @param[in] node Softmax node to visit + * @return N/A + */ + virtual void visit(const Softmax::Node &) = 0; + /** + * @brief Visit a ReduceMax node + * @param[in] node ReduceMax node to visit + * @return N/A + */ + virtual void visit(const ReduceMax::Node &) = 0; + /** + * @brief Visit a ReduceMin node + * @param[in] node ReduceMin node to visit + * @return N/A + */ + virtual void visit(const ReduceMin::Node &) = 0; + /** + * @brief Visit a Cast node + * @param[in] node Cast node to visit + * @return N/A + */ + virtual void visit(const Cast::Node &) = 0; + /** + * @brief Visit a TopKV2 node + * @param[in] node TopKV2 node to visit + * @return N/A + */ + virtual void visit(const TopKV2::Node &) = 0; + /** + * @brief Visit a Gather node + * @param[in] node Gather node to visit + * @return N/A + */ + virtual void visit(const Gather::Node &) = 0; + /** + * @brief Visit an PReLU node + * @param[in] node PReLU node to visit + * @return N/A + */ + virtual void visit(const PReLU::Node &) = 0; + /** + * @brief Visit an ReLU node + * @param[in] node Relu node to visit + * @return N/A + */ + virtual void visit(const ReLU::Node &) = 0; + /** + * @brief Visit a ReLU1 node + * @param[in] node ReLU1 node to visit + * @return N/A + */ + virtual void visit(const ReLU1::Node &) = 0; + /** + * @brief Visit a ReLU6 node + * @param[in] node ReLU6 node to visit + * @return N/A + */ + virtual void visit(const ReLU6::Node &) = 0; + /** + * @brief Visit a Tanh node + * @param[in] node Tanh node to visit + * @return N/A + */ + virtual void visit(const Tanh::Node &) = 0; + /** + * @brief Visit a Squeeze node + * @param[in] node Squeeze node to visit + * @return N/A + */ + virtual void visit(const Squeeze::Node &) = 0; + /** + * @brief Visit an Logistic node + * @param[in] node Logistic node to visit + * @return N/A + */ + virtual void visit(const Logistic::Node &) = 0; + /** + * @brief Visit a Mean node + * @param[in] node Mean node to visit + * @return N/A + */ + virtual void visit(const Mean::Node &) = 0; + /** + * @brief Visit an RNN node + * @param[in] node RNN node to visit + * @return N/A + */ + virtual void visit(const RNN::Node &) = 0; + /** + * @brief Visit a Transpose node + * @param[in] node Transpose node to visit + * @return N/A + */ + virtual void visit(const Transpose::Node &) = 0; + /** + * @brief Visit an LSTM node + * @param[in] node LSTM node to visit + * @return N/A + */ + virtual void visit(const LSTM::Node &) = 0; + /** + * @brief Visit a Floor node + * @param[in] node Floor node to visit + * @return N/A + */ + virtual void visit(const Floor::Node &) = 0; + /** + * @brief Visit a Split node + * @param[in] node Split node to visit + * @return N/A + */ + virtual void visit(const Split::Node &) = 0; + /** + * @brief Visit an RSQRT node + * @param[in] node RSQRT node to visit + * @return N/A + */ + virtual void visit(const RSQRT::Node &) = 0; + /** + * @brief Visit an SQRT node + * @param[in] node SQRT node to visit + * @return N/A + */ + virtual void visit(const SQRT::Node &) = 0; + /** + * @brief Visit a Pad node + * @param[in] node Pad node to visit + * @return N/A + */ + virtual void visit(const Pad::Node &) = 0; + /** + * @brief Visit a SpaceToDepth node + * @param[in] node SpaceToDepth node to visit + * @return N/A + */ + virtual void visit(const SpaceToDepth::Node &) = 0; + /** + * @brief Visit a SpaceToBatchND node + * @param[in] node SpaceToBatchND node to visit + * @return N/A + */ + virtual void visit(const SpaceToBatchND::Node &) = 0; + /** + * @brief Visit an L2Pool2D node with implicit padding + * @param[in] node L2Pool2D node to visit + * @return N/A + */ + virtual void visit(const L2Pool2D::Implicit::Node &) = 0; + /** + * @brief Visit an L2Pool2D node with explicit padding + * @param[in] node L2Pool2D node to visit + * @return N/A + */ + virtual void visit(const L2Pool2D::Explicit::Node &) = 0; + /** + * @brief Visit an EmbeddingLookup node + * @param[in] node EmbeddingLookup node to visit + * @return N/A + */ + virtual void visit(const EmbeddingLookup::Node &) = 0; + /** + * @brief Visit a HashtableLookup node + * @param[in] node HashtableLookup node to visit + * @return N/A + */ + virtual void visit(const HashtableLookup::Node &) = 0; + /** + * @brief Visit an L2Normalization node + * @param[in] node L2Normalization node to visit + * @return N/A + */ + virtual void visit(const L2Normalization::Node &) = 0; + /** + * @brief Visit a SquaredDifference node + * @param[in] node SquaredDifference node to visit + * @return N/A + */ + virtual void visit(const SquaredDifference::Node &) = 0; + /** + * @brief Visit a LocalResponseNormalization node + * @param[in] node LocalResponseNormalization node to visit + * @return N/A + */ + virtual void visit(const LocalResponseNormalization::Node &) = 0; + /** + * @brief Visit a DepthToSpace node + * @param[in] node DepthToSpace node to visit + * @return N/A + */ + virtual void visit(const DepthToSpace::Node &) = 0; + /** + * @brief Visit a Unpack node + * @param[in] node Unpack node to visit + * @return N/A + */ + virtual void visit(const Unpack::Node &) = 0; + /** + * @brief Visit a Neg node + * @param[in] node Neg node to visit + * @return N/A + */ + virtual void visit(const Neg::Node &) = 0; + /** + * @brief Visit a Exp node + * @param[in] node Exp node to visit + * @return N/A + */ + virtual void visit(const Exp::Node &) = 0; + /** + * @brief Visit a ReduceSum node + * @param[in] node ReduceSum node to visit + * @return N/A + */ + virtual void visit(const ReduceSum::Node &) = 0; + /** + * @brief Visit a Equal node + * @param[in] node Equal node to visit + * @return N/A + */ + virtual void visit(const Equal::Node &) = 0; + /** + * @brief Visit a BatchToSpaceNd node + * @param[in] node BatchToSpaceNd node to visit + * @return N/A + */ + virtual void visit(const BatchToSpaceNd::Node &) = 0; + /** + * @brief Visit a TransposeConv node + * @param[in] node TransposeConv node to visit + * @return N/A + */ + virtual void visit(const TransposeConv::Node &) = 0; + /** + * @brief Visit a Pack node + * @param[in] node Pack node to visit + * @return N/A + */ + virtual void visit(const Pack::Node &) = 0; + /** + * @brief Visit a Abs node + * @param[in] node Abs node to visit + * @return N/A + */ + virtual void visit(const Abs::Node &) = 0; + /** + * @brief Visit a NotEqual node + * @param[in] node NotEqual node to visit + * @return N/A + */ + virtual void visit(const NotEqual::Node &) = 0; + /** + * @brief Visit a LogicalAnd node + * @param[in] node LogicalAnd node to visit + * @return N/A + */ + virtual void visit(const LogicalAnd::Node &) = 0; + /** + * @brief Visit a LogicalNot node + * @param[in] node LogicalNot node to visit + * @return N/A + */ + virtual void visit(const LogicalNot::Node &) = 0; + /** + * @brief Visit a LogicalOr node + * @param[in] node LogicalOr node to visit + * @return N/A + */ + virtual void visit(const LogicalOr::Node &) = 0; +}; + +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_NODE_VISITOR_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/NotEqual.cc b/runtime/contrib/pure_arm_compute/src/internal/op/NotEqual.cc new file mode 100644 index 000000000..2906e214b --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/NotEqual.cc @@ -0,0 +1,65 @@ +/* + * 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 "internal/op/NotEqual.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace NotEqual +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace NotEqual +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace NotEqual +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 2 && outputCount == 1); + + output_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> input1 Tensor Index + // 1 -> input2 Tensor Index + input1_index = inputs[0]; + input2_index = inputs[1]; +} + +} // namespace NotEqual +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/NotEqual.h b/runtime/contrib/pure_arm_compute/src/internal/op/NotEqual.h new file mode 100644 index 000000000..0d6130948 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/NotEqual.h @@ -0,0 +1,83 @@ +/* + * 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 __INTERNAL_OP_NOT_EQUAL_H__ +#define __INTERNAL_OP_NOT_EQUAL_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace NotEqual +{ + +struct Param +{ + int32_t output_index; + + int32_t input1_index; + int32_t input2_index; + + Param() = default; + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +} // namespace NotEqual +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace NotEqual +{ +class Node final : public op::Node +{ +public: + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + virtual ~Node() = default; + +public: + const Param ¶m(void) const { return _param; } + +public: + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace NotEqual +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_NOT_EQUAL_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/PReLU.cc b/runtime/contrib/pure_arm_compute/src/internal/op/PReLU.cc new file mode 100644 index 000000000..25b06505b --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/PReLU.cc @@ -0,0 +1,65 @@ +/* + * 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 "internal/op/PReLU.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace PReLU +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace PReLU +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace PReLU +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 2 && outputCount == 1); + + ofm_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> input Tensor Index + // 1 -> alpha Tensor Index + ifm_index = inputs[0]; + alpha_index = inputs[1]; +} + +} // namespace PReLU +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/PReLU.h b/runtime/contrib/pure_arm_compute/src/internal/op/PReLU.h new file mode 100644 index 000000000..ae754abb4 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/PReLU.h @@ -0,0 +1,109 @@ +/* + * 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. + */ + +/** + * @file ReLU.h + * @brief This file contains accept function and params for ReLU operation + * @ingroup COM_AI_RUNTIME + */ + +#ifndef __INTERNAL_OP_PRELU_H__ +#define __INTERNAL_OP_PRELU_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace PReLU +{ + +/** + * @brief Struct of PReLU operation's param + */ +struct Param +{ + int32_t ofm_index; /**< Output format index */ + + int32_t ifm_index; /**< Input format index */ + int32_t alpha_index; /**< Alpha input index */ + + /** + * @brief Construct a new Param object for ReLU as default + */ + Param() = default; + + /** + * @brief Construct a new Param object for PReLU with params + * @param [in] inputCount The number of input + * @param [in] inputs Array containing inputs + * @param [in] outputCount The number of output + * @param [in] outputs Array containing outputs + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to define operation node for PReLU + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new Node object for PReLU with param + * @param [in] param Parameters for Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Destroy the Node object for PReLU + */ + virtual ~Node() = default; + +public: + /** + * @brief Get parameters for PReLU + * @return Parameters of PReLU + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Function for accepting node for PReLU + * @param [in] v Node visitor for invoking visit function of PReLU + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace PReLU +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_PRELU_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Pack.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Pack.cc new file mode 100644 index 000000000..73f89b840 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Pack.cc @@ -0,0 +1,69 @@ +/* + * 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 "internal/op/Pack.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Pack +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace Pack +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Pack +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(outputCount == 1); + + // Each input should be interpreted as follows: + // + // 0 .. n - 3 -> Input Tensor Index + // n - 2 -> Input Tensor counts (will be ignored) + // n - 1 -> Input Axis Index + ofm_index = outputs[0]; + axis_index = inputs[inputCount - 1]; + // last input is axis along which packing is required + for (uint32_t n = 0; n < inputCount - 2; ++n) + { + ifm_indexes.emplace_back(inputs[n]); + } +} + +} // namespace Pack +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Pack.h b/runtime/contrib/pure_arm_compute/src/internal/op/Pack.h new file mode 100644 index 000000000..c5de01bd8 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Pack.h @@ -0,0 +1,72 @@ +/* + * 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 __INTERNAL_OP_PACK_H__ +#define __INTERNAL_OP_PACK_H__ + +#include "internal/op/Node.h" +#include <vector> + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Pack +{ + +struct Param +{ + int32_t ofm_index; + // There are N+1 inputs, 0 to N-1 are tensors of same shape + // Nth input is axis index along which stack is needed to be done. + std::vector<int32_t> ifm_indexes; + int32_t axis_index; + + Param() = default; + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +class Node final : public op::Node +{ +public: + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + virtual ~Node() = default; + +public: + const Param ¶m(void) const { return _param; } + +public: + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace Pack +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_PACK_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Pad.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Pad.cc new file mode 100644 index 000000000..00938242b --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Pad.cc @@ -0,0 +1,63 @@ +/* + * 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 "internal/op/Pad.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Pad +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace Pad +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Pad +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 2 && outputCount == 1); + ofm_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> input Tensor Index + // 1 -> paddings + ifm_index = inputs[0]; + paddings_index = inputs[1]; +} +} // namespace Pad +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Pad.h b/runtime/contrib/pure_arm_compute/src/internal/op/Pad.h new file mode 100644 index 000000000..68752a10e --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Pad.h @@ -0,0 +1,107 @@ +/* + * 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. + */ + +/** + * @file Pad.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines Pad node + */ + +#ifndef __INTERNAL_OP_PAD_H__ +#define __INTERNAL_OP_PAD_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Pad +{ + +/** + * @brief Struct to manipulate parameter for Pad operation + */ +struct Param +{ + int32_t ifm_index; //!< index for input + int32_t paddings_index; //!< index for padding + int32_t ofm_index; //!< index for output + + /** + * @brief Default Constructor + */ + Param() = default; + /** + * @brief Construct a new Param object + * @param[in] inputCount the number of inputs + * @param[in] inputs pointer for input data + * @param[in] outputCount the number of outputs + * @param[in] outputs pointer for input data + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to define Pad Operation + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new RNN Node object + * @param param Parameter for RNN Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Default Destructor + */ + virtual ~Node() = default; + +public: + /** + * @brief Get parameter + * @return Param reference + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Accept a NodeVisitor so that it can visit this node + * @param [in] v Visitor + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; //!< parameter for Pad node +}; + +} // namespace Pad +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_PAD_H_ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/RSQRT.cc b/runtime/contrib/pure_arm_compute/src/internal/op/RSQRT.cc new file mode 100644 index 000000000..d79563d14 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/RSQRT.cc @@ -0,0 +1,62 @@ +/* + * 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 "internal/op/RSQRT.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace RSQRT +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace RSQRT +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace RSQRT +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 1 && outputCount == 1); + + output_index = outputs[0]; + + // Each input should be interpreted as follows: + // 0 -> input Tensor Index + input_index = inputs[0]; +} + +} // namespace RSQRT +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/RSQRT.h b/runtime/contrib/pure_arm_compute/src/internal/op/RSQRT.h new file mode 100644 index 000000000..e39d60241 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/RSQRT.h @@ -0,0 +1,105 @@ +/* + * 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. + */ + +/** + * @file RSQRT.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines internal::tflite::op::RSQRT::Param struct + * and internal::tflite::op::RSQRT::Node class + */ +#ifndef __INTERNAL_OP_RSQRT_H__ +#define __INTERNAL_OP_RSQRT_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace RSQRT +{ + +/** + * @brief Struct to have indexes for operation parameter + */ +struct Param +{ + int32_t output_index; /**< Index of output feature map */ + + int32_t input_index; /**< Index of input feature map */ + /** + * @brief Construct as default + */ + Param() = default; + /** + * @brief Construct a new Param object with params + * @param[in] inputCount Count of inputs + * @param[in] inputs Pointer of inputs + * @param[in] outputCount Count of outputs + * @param[in] outputs Pointer of outputs + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to represent an operation of data structure + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new Node object with param + * @param[in] param Param object that makes up a Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Destruct as default + */ + virtual ~Node() = default; + +public: + /** + * @brief Get a reference of Param object + * @return Reference of Param object + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Visit this Node by NodeVisitor + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace RSQRT +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_RSQRT_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/ReLU.cc b/runtime/contrib/pure_arm_compute/src/internal/op/ReLU.cc new file mode 100644 index 000000000..2f48372af --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/ReLU.cc @@ -0,0 +1,63 @@ +/* + * 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 "internal/op/ReLU.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace ReLU +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace ReLU +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace ReLU +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 1 && outputCount == 1); + + ofm_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> input Tensor Index + ifm_index = inputs[0]; +} + +} // namespace ReLU +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/ReLU.h b/runtime/contrib/pure_arm_compute/src/internal/op/ReLU.h new file mode 100644 index 000000000..aaa39b523 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/ReLU.h @@ -0,0 +1,108 @@ +/* + * 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. + */ + +/** + * @file ReLU.h + * @brief This file contains accept function and params for ReLU operation + * @ingroup COM_AI_RUNTIME + */ + +#ifndef __INTERNAL_OP_RELU_H__ +#define __INTERNAL_OP_RELU_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace ReLU +{ + +/** + * @brief Struct of ReLU operation's param + */ +struct Param +{ + int32_t ofm_index; /**< Output format index */ + + int32_t ifm_index; /**< Input format index */ + + /** + * @brief Construct a new Param object for ReLU as default + */ + Param() = default; + + /** + * @brief Construct a new Param object for ReLU with params + * @param [in] inputCount The number of input + * @param [in] inputs Array containing inputs + * @param [in] outputCount The number of output + * @param [in] outputs Array containing outputs + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to define operation node for ReLU + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new Node object for ReLU with param + * @param [in] param Parameters for Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Destroy the Node object for ReLU + */ + virtual ~Node() = default; + +public: + /** + * @brief Get parameters for ReLU + * @return Parameters of ReLU + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Function for accepting node for ReLU + * @param [in] v Node visitor for invoking visit function of ReLU + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace ReLU +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_RELU_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/ReLU1.cc b/runtime/contrib/pure_arm_compute/src/internal/op/ReLU1.cc new file mode 100644 index 000000000..1925ac404 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/ReLU1.cc @@ -0,0 +1,63 @@ +/* + * 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 "internal/op/ReLU1.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace ReLU1 +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace ReLU1 +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace ReLU1 +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 1 && outputCount == 1); + + ofm_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> input Tensor Index + ifm_index = inputs[0]; +} + +} // namespace ReLU1 +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/ReLU1.h b/runtime/contrib/pure_arm_compute/src/internal/op/ReLU1.h new file mode 100644 index 000000000..330445af8 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/ReLU1.h @@ -0,0 +1,108 @@ +/* + * 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. + */ + +/** + * @file ReLU1.h + * @brief This file contains accept function and params for ReLU1 operation + * @ingroup COM_AI_RUNTIME + */ + +#ifndef __INTERNAL_OP_RELU1_H__ +#define __INTERNAL_OP_RELU1_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace ReLU1 +{ + +/** + * @brief Struct of ReLU1 operation's param + */ +struct Param +{ + int32_t ofm_index; /**< Output format index */ + + int32_t ifm_index; /**< Input format index */ + + /** + * @brief Construct a new Param object for ReLU1 as default + */ + Param() = default; + + /** + * @brief Construct a new Param object for ReLU1 with params + * @param [in] inputCount The number of input + * @param [in] inputs Array containing inputs + * @param [in] outputCount The number of output + * @param [in] outputs Array containing outputs + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to define operation node for ReLU1 + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new Node object for ReLU1 with param + * @param [in] param Parameters for Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Destroy the Node object for ReLU1 + */ + virtual ~Node() = default; + +public: + /** + * @brief Get parameters for ReLU1 + * @return Parameters of ReLU1 + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Function for accepting node for ReLU1 + * @param [in] v Node visitor for invoking visit function of ReLU1 + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace ReLU1 +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_RELU1_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/ReLU6.cc b/runtime/contrib/pure_arm_compute/src/internal/op/ReLU6.cc new file mode 100644 index 000000000..e94ddcf15 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/ReLU6.cc @@ -0,0 +1,63 @@ +/* + * 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 "internal/op/ReLU6.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace ReLU6 +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace ReLU6 +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace ReLU6 +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 1 && outputCount == 1); + + ofm_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> input Tensor Index + ifm_index = inputs[0]; +} + +} // namespace ReLU6 +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/ReLU6.h b/runtime/contrib/pure_arm_compute/src/internal/op/ReLU6.h new file mode 100644 index 000000000..6fc2c24fe --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/ReLU6.h @@ -0,0 +1,104 @@ +/* + * 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. + */ + +/** + * @file ReLU6.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines internal::tflite::op::ReLU6 class + */ +#ifndef __INTERNAL_OP_RELU6_H__ +#define __INTERNAL_OP_RELU6_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace ReLU6 +{ + +/** + * @brief Struct to have indexes for operation parameter + */ +struct Param +{ + int32_t ofm_index; /** Index of output feature map */ + + int32_t ifm_index; /** Index of input feature map */ + /** + * @brief Construct as default + */ + Param() = default; + /** + * @brief Construct a new Param object with params + * @param[in] inputCount Count of inputs + * @param[in] inputs Pointer of inputs + * @param[in] outputCount Count of outputs + * @param[in] outputs Pointer of outputs + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to represent an operation of data structure + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new Node object with param + * @param[in] param Param object that makes up a Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Destruct as default + */ + virtual ~Node() = default; + +public: + /** + * @brief Get a reference of Param object + * @return Reference of Param object + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Visit this Node by NodeVisitor + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace ReLU6 +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_RELU6_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/ReduceMax.cc b/runtime/contrib/pure_arm_compute/src/internal/op/ReduceMax.cc new file mode 100644 index 000000000..7a337eabf --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/ReduceMax.cc @@ -0,0 +1,65 @@ +/* + * 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 "internal/op/ReduceMax.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace ReduceMax +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace ReduceMax +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace ReduceMax +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 2 && outputCount == 1); + + ofm_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> Input Tensor Index + // 1 -> Axis Tensor Index + ifm_index = inputs[0]; + axis_index = inputs[1]; +} + +} // namespace ReduceMax +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/ReduceMax.h b/runtime/contrib/pure_arm_compute/src/internal/op/ReduceMax.h new file mode 100644 index 000000000..77d8bd869 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/ReduceMax.h @@ -0,0 +1,107 @@ +/* + * 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. + */ + +/** + * @file ReduceMax.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines internal::tflite::op::ReduceMax::Param struct + * and internal::tflite::op::ReduceMax::Node class + */ +#ifndef __INTERNAL_OP_REDUCEMAX_H__ +#define __INTERNAL_OP_REDUCEMAX_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace ReduceMax +{ + +/** + * @brief Struct to have indexes for operation parameter + */ +struct Param +{ + int32_t ofm_index; /**< Index of output feature map */ + + int32_t ifm_index; /**< Index of input feature map */ + int32_t axis_index; /**< Index of axis */ + /** + * @brief Construct as default + */ + Param() = default; + /** + * @brief Construct a new Param object with params + * @param[in] inputCount Count of inputs + * @param[in] inputs Pointer of inputs + * @param[in] outputCount Count of outputs + * @param[in] outputs Pointer of outputs + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to represent an operation of data structure + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new Node object with param + * @param[in] param Param object that makes up a Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Destruct as default + */ + virtual ~Node() = default; + +public: + /** + * @brief Get a reference of Param object + * @return Reference of Param object + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Visit this Node by NodeVisitor + * @param[in] v Visitor + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace ReduceMax +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_REDUCEMAX_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/ReduceMin.cc b/runtime/contrib/pure_arm_compute/src/internal/op/ReduceMin.cc new file mode 100644 index 000000000..72b6079d4 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/ReduceMin.cc @@ -0,0 +1,65 @@ +/* + * 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 "internal/op/ReduceMin.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace ReduceMin +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace ReduceMin +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace ReduceMin +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 2 && outputCount == 1); + + ofm_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> Input Tensor Index + // 1 -> Axis Tensor Index + ifm_index = inputs[0]; + axis_index = inputs[1]; +} + +} // namespace ReduceMin +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/ReduceMin.h b/runtime/contrib/pure_arm_compute/src/internal/op/ReduceMin.h new file mode 100644 index 000000000..5dd82ec43 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/ReduceMin.h @@ -0,0 +1,107 @@ +/* + * 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. + */ + +/** + * @file ReduceMin.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines internal::tflite::op::ReduceMin::Param struct + * and internal::tflite::op::ReduceMin::Node class + */ +#ifndef __INTERNAL_OP_REDUCEMIN_H__ +#define __INTERNAL_OP_REDUCEMIN_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace ReduceMin +{ + +/** + * @brief Struct to have indexes for operation parameter + */ +struct Param +{ + int32_t ofm_index; /**< Index of output feature map */ + + int32_t ifm_index; /**< Index of input feature map */ + int32_t axis_index; /**< Index of axis */ + /** + * @brief Construct as default + */ + Param() = default; + /** + * @brief Construct a new Param object with params + * @param[in] inputCount Count of inputs + * @param[in] inputs Pointer of inputs + * @param[in] outputCount Count of outputs + * @param[in] outputs Pointer of outputs + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to represent an operation of data structure + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new Node object with param + * @param[in] param Param object that makes up a Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Destruct as default + */ + virtual ~Node() = default; + +public: + /** + * @brief Get a reference of Param object + * @return Reference of Param object + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Visit this Node by NodeVisitor + * @param[in] v Visitor + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace ReduceMin +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_REDUCEMIN_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/ReduceSum.cc b/runtime/contrib/pure_arm_compute/src/internal/op/ReduceSum.cc new file mode 100644 index 000000000..4d83c1734 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/ReduceSum.cc @@ -0,0 +1,65 @@ +/* + * 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 "internal/op/ReduceSum.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace ReduceSum +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace ReduceSum +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace ReduceSum +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 2 && outputCount == 1); + + ofm_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> Input Tensor Index + // 1 -> Axis Tensor Index + ifm_index = inputs[0]; + axis_index = inputs[1]; +} + +} // namespace ReduceSum +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/ReduceSum.h b/runtime/contrib/pure_arm_compute/src/internal/op/ReduceSum.h new file mode 100644 index 000000000..9c661f63a --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/ReduceSum.h @@ -0,0 +1,70 @@ +/* + * 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 __INTERNAL_OP_REDUCESUM_H__ +#define __INTERNAL_OP_REDUCESUM_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace ReduceSum +{ + +struct Param +{ + int32_t ofm_index; + + int32_t ifm_index; + int32_t axis_index; + + Param() = default; + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +class Node final : public op::Node +{ +public: + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + virtual ~Node() = default; + +public: + const Param ¶m(void) const { return _param; } + +public: + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace ReduceSum +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_REDUCESUM_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Reshape.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Reshape.cc new file mode 100644 index 000000000..862ed30c7 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Reshape.cc @@ -0,0 +1,66 @@ +/* + * 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 "internal/op/Reshape.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Reshape +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace Reshape +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Reshape +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 2 && outputCount == 1); + + output_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> A tensor, specifying the tensor to be reshaped. + // 1 -> A 1-D tensor of type ANEURALNETWORKS_TENSOR_INT32, defining the shape of the output + // tensor + input_index = inputs[0]; + shape_index = inputs[1]; +} + +} // namespace Reshape +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Reshape.h b/runtime/contrib/pure_arm_compute/src/internal/op/Reshape.h new file mode 100644 index 000000000..7152eaece --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Reshape.h @@ -0,0 +1,108 @@ +/* + * 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. + */ + +/** + * @file Reshape.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines Reshape node + */ + +#ifndef __INTERNAL_OP_RESHAPE_H__ +#define __INTERNAL_OP_RESHAPE_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Reshape +{ + +/** + * @brief Struct to manipulate parameter for Reshape operation + */ +struct Param +{ + int32_t output_index; //!< index for output feature map + + int32_t input_index; //!< index for input feature map + int32_t shape_index; //!< index for shape + + /** + * @brief Default Constructor + */ + Param() = default; + /** + * @brief Construct a new Param object + * @param[in] inputCount the number of inputs + * @param[in] inputs pointer for input data + * @param[in] outputCount the number of outputs + * @param[in] outputs pointer for input data + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to define Reshape Operation + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new Reshape Node object + * @param param Parameter for Reshape Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Default Destructor + */ + virtual ~Node() = default; + +public: + /** + * @brief Get parameter + * @return Param reference + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Accept a NodeVisitor so that it can visit this node + * @param [in] v Visitor + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; //!< parameter for Reshape node +}; + +} // namespace Reshape +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_RESHAPE_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/ResizeBilinear.cc b/runtime/contrib/pure_arm_compute/src/internal/op/ResizeBilinear.cc new file mode 100644 index 000000000..02ec20cb1 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/ResizeBilinear.cc @@ -0,0 +1,67 @@ +/* + * 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 "internal/op/ResizeBilinear.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace ResizeBilinear +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace ResizeBilinear +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace ResizeBilinear +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 3 && outputCount == 1); + + ofm_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> IFM Index + // 1 -> Height Index + // 2 -> Width Index + ifm_index = inputs[0]; + height_index = inputs[1]; + width_index = inputs[2]; +} + +} // namespace ResizeBilinear +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/ResizeBilinear.h b/runtime/contrib/pure_arm_compute/src/internal/op/ResizeBilinear.h new file mode 100644 index 000000000..f2eab4aaf --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/ResizeBilinear.h @@ -0,0 +1,108 @@ +/* + * 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. + */ + +/** + * @file ResizeBilinear.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines internal::tflite::op::ResizeBilinear::Param struct + * and internal::tflite::op::ResizeBilinear::Node class + */ +#ifndef __INTERNAL_OP_RESIZE_BILINEAR_H__ +#define __INTERNAL_OP_RESIZE_BILINEAR_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace ResizeBilinear +{ + +/** + * @brief Struct to have indexes for ResizeBilinear operation parameter + */ +struct Param +{ + int32_t ofm_index; /**< Index of output feature map */ + + int32_t ifm_index; /**< Index of input feature map */ + int32_t height_index; /**< Index of height */ + int32_t width_index; /**< Index of width */ + /** + * @brief Construct as default + */ + Param() = default; + /** + * @brief Construct a new Param object with params + * @param[in] inputCount Count of inputs + * @param[in] inputs Pointer of inputs + * @param[in] outputCount Count of outputs + * @param[in] outputs Pointer of outputs + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to represent an ResizeBilinear operation of data structure + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new Node object with param + * @param[in] param Param object that makes up a Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Destruct as default + */ + virtual ~Node() = default; + +public: + /** + * @brief Get a reference of Param object + * @return Reference of Param object + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Visit this Node by NodeVisitor + * @param[in] v Visitor + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace ResizeBilinear +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_RESIZE_BILINEAR_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Rnn.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Rnn.cc new file mode 100644 index 000000000..3f19fca3b --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Rnn.cc @@ -0,0 +1,66 @@ +/* + * 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 "internal/op/Rnn.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace RNN +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace RNN +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace RNN +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 6 && outputCount == 2); + + output_index = outputs[0]; + hidden_state_out_index = outputs[1]; + + input_index = inputs[0]; + weights_index = inputs[1]; + recurrent_weights_index = inputs[2]; + bias_index = inputs[3]; + hidden_state_in_index = inputs[4]; + fused_activation_index = inputs[5]; +} + +} // namespace RNN +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Rnn.h b/runtime/contrib/pure_arm_compute/src/internal/op/Rnn.h new file mode 100644 index 000000000..7b2a10843 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Rnn.h @@ -0,0 +1,113 @@ +/* + * 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. + */ + +/** + * @file Rnn.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines RNN node + */ + +#ifndef __INTERNAL_OP_RNN_H__ +#define __INTERNAL_OP_RNN_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace RNN +{ + +/** + * @brief Struct to manipulate parameter for RNN operation + */ +struct Param +{ + int32_t output_index; //!< index for ouuput + int32_t hidden_state_out_index; //!< index for hidden state output + + int32_t input_index; //!< index for input + int32_t weights_index; //!< index for weight + int32_t recurrent_weights_index; //!< index for recurrent weights + int32_t bias_index; //!< index for bias + int32_t hidden_state_in_index; //!< index for hidden state input + int32_t fused_activation_index; //!< index for fused activation + + /** + * @brief Default Constructor + */ + Param() = default; + /** + * @brief Construct a new Param object + * @param[in] inputCount the number of inputs + * @param[in] inputs pointer for input data + * @param[in] outputCount the number of outputs + * @param[in] outputs pointer for input data + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to define RNN Operation + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new RNN Node object + * @param param Parameter for RNN Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Default Destructor + */ + virtual ~Node() = default; + +public: + /** + * @brief Get parameter + * @return Param reference + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Accept a NodeVisitor so that it can visit this node + * @param [in] v Visitor + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; //!< parameter for RNN node +}; + +} // namespace RNN +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_RNN_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/SQRT.cc b/runtime/contrib/pure_arm_compute/src/internal/op/SQRT.cc new file mode 100644 index 000000000..70ce42e9c --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/SQRT.cc @@ -0,0 +1,62 @@ +/* + * 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 "internal/op/SQRT.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace SQRT +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace SQRT +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace SQRT +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 1 && outputCount == 1); + + output_index = outputs[0]; + + // Each input should be interpreted as follows: + // 0 -> input Tensor Index + input_index = inputs[0]; +} + +} // namespace SQRT +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/SQRT.h b/runtime/contrib/pure_arm_compute/src/internal/op/SQRT.h new file mode 100644 index 000000000..85dfb97a7 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/SQRT.h @@ -0,0 +1,105 @@ +/* + * 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. + */ + +/** + * @file SQRT.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines internal::tflite::op::SQRT::Param struct + * and internal::tflite::op::SQRT::Node class + */ +#ifndef __INTERNAL_OP_SQRT_H__ +#define __INTERNAL_OP_SQRT_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace SQRT +{ + +/** + * @brief Struct to have indexes for operation parameter + */ +struct Param +{ + int32_t output_index; /**< Index of output feature map */ + + int32_t input_index; /**< Index of input feature map */ + /** + * @brief Construct as default + */ + Param() = default; + /** + * @brief Construct a new Param object with params + * @param[in] inputCount Count of inputs + * @param[in] inputs Pointer of inputs + * @param[in] outputCount Count of outputs + * @param[in] outputs Pointer of outputs + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to represent an operation of data structure + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new Node object with param + * @param[in] param Param object that makes up a Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Destruct as default + */ + virtual ~Node() = default; + +public: + /** + * @brief Get a reference of Param object + * @return Reference of Param object + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Visit this Node by NodeVisitor + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace SQRT +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_SQRT_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Softmax.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Softmax.cc new file mode 100644 index 000000000..516a0fa04 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Softmax.cc @@ -0,0 +1,65 @@ +/* + * 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 "internal/op/Softmax.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Softmax +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace Softmax +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Softmax +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 2 && outputCount == 1); + + output_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> A 2-D or 4-D tensor, specifying the tensor to be reshaped. + // 1 -> FLOAT32 value, specifying the positive scaling factor for the exponent, beta. + input_index = inputs[0]; + scale_index = inputs[1]; +} + +} // namespace Softmax +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Softmax.h b/runtime/contrib/pure_arm_compute/src/internal/op/Softmax.h new file mode 100644 index 000000000..6e631af5f --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Softmax.h @@ -0,0 +1,109 @@ +/* + * 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. + */ + +/** + * @file Softmax.h + * @brief This file contains accept function and params for Softmax operation + * @ingroup COM_AI_RUNTIME + */ + +#ifndef __INTERNAL_OP_SOFTMAX_H__ +#define __INTERNAL_OP_SOFTMAX_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Softmax +{ + +/** + * @brief Struct of Softmax operation's param + */ +struct Param +{ + int32_t output_index; /**< Output index */ + + int32_t input_index; /**< Input index */ + int32_t scale_index; /**< Scale index */ + + /** + * @brief Construct a new Param object for Softmax as default + */ + Param() = default; + + /** + * @brief Construct a new Param object for Softmax with params + * @param [in] inputCount The number of input + * @param [in] inputs Array containing inputs + * @param [in] outputCount The number of output + * @param [in] outputs Array containing outputs + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to define operation node for Softmax + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new Node object for Softmax with param + * @param [in] param Parameters for Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Destroy the Node object for Softmax + */ + virtual ~Node() = default; + +public: + /** + * @brief Get parameters for Softmax + * @return Parameters of Softmax + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Function for accepting node for Softmax + * @param [in] v Node visitor for invoking visit function of Softmax + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace Softmax +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_SOFTMAX_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/SpaceToBatchND.cc b/runtime/contrib/pure_arm_compute/src/internal/op/SpaceToBatchND.cc new file mode 100644 index 000000000..9ab026cf4 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/SpaceToBatchND.cc @@ -0,0 +1,67 @@ +/* + * 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 "internal/op/SpaceToBatchND.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace SpaceToBatchND +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace SpaceToBatchND +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace SpaceToBatchND +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 3 && outputCount == 1); + + output_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> Input Tensor Index + // 1 -> Block size Index + // 2 -> Padding size Index + input_index = inputs[0]; + block_size_index = inputs[1]; + padding_size_index = inputs[2]; +} + +} // namespace SpaceToBatchND +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/SpaceToBatchND.h b/runtime/contrib/pure_arm_compute/src/internal/op/SpaceToBatchND.h new file mode 100644 index 000000000..650d068f4 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/SpaceToBatchND.h @@ -0,0 +1,71 @@ +/* + * 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 __INTERNAL_OP_SPACETOBATCHND_H__ +#define __INTERNAL_OP_SPACETOBATCHND_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace SpaceToBatchND +{ + +struct Param +{ + int32_t output_index; + + int32_t input_index; + int32_t block_size_index; + int32_t padding_size_index; + + Param() = default; + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +class Node final : public op::Node +{ +public: + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + virtual ~Node() = default; + +public: + const Param ¶m(void) const { return _param; } + +public: + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace SpaceToBatchND +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_SPACETOBATCHND_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/SpaceToDepth.cc b/runtime/contrib/pure_arm_compute/src/internal/op/SpaceToDepth.cc new file mode 100644 index 000000000..2fb587be0 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/SpaceToDepth.cc @@ -0,0 +1,65 @@ +/* + * 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 "internal/op/SpaceToDepth.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace SpaceToDepth +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace SpaceToDepth +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace SpaceToDepth +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 2 && outputCount == 1); + + output_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> Input Tensor Index + // 1 -> Block size Index + input_index = inputs[0]; + block_size_index = inputs[1]; +} + +} // namespace SpaceToDepth +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/SpaceToDepth.h b/runtime/contrib/pure_arm_compute/src/internal/op/SpaceToDepth.h new file mode 100644 index 000000000..2e624006a --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/SpaceToDepth.h @@ -0,0 +1,109 @@ +/* + * 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. + */ + +/** + * @file SpaceToDepth.h + * @brief This file contains accept function and params for SpaceToDepth operation + * @ingroup COM_AI_RUNTIME + */ + +#ifndef __INTERNAL_OP_SPACETODEPTH_H__ +#define __INTERNAL_OP_SPACETODEPTH_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace SpaceToDepth +{ + +/** + * @brief Struct of SpaceToDepth operation's param + */ +struct Param +{ + int32_t output_index; /**< Output index */ + + int32_t input_index; /**< Input index */ + int32_t block_size_index; /**< Block size index */ + + /** + * @brief Construct a new Param object for SpaceToDepth as default + */ + Param() = default; + + /** + * @brief Construct a new Param object for SpaceToDepth with params + * @param [in] inputCount The number of input + * @param [in] inputs Array containing inputs + * @param [in] outputCount The number of output + * @param [in] outputs Array containing outputs + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to define operation node for SpaceToDepth + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new Node object for SpaceToDepth with param + * @param [in] param Parameters for Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Destroy the Node object for SpaceToDepth + */ + virtual ~Node() = default; + +public: + /** + * @brief Get parameters for SpaceToDepth + * @return Parameters of SpaceToDepth + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Function for accepting node for SpaceToDepth + * @param [in] v Node visitor for invoking visit function of SpaceToDepth + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace SpaceToDepth +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_SPACETODEPTH_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Split.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Split.cc new file mode 100644 index 000000000..6457a106a --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Split.cc @@ -0,0 +1,72 @@ +/* + * 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 "internal/op/Split.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Split +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace Split +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Split +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 3); + + // Each input should be interpreted as follows: + // 0 -> An n-D tensor, specifying the tensor to be split. + // 1 -> A 0-D int32 tensor, indicating the dimension along which to split. + // 2 -> A 0-D int32 tensor, indicating the number of outputs + // (It can be ignored on pacl becasue pacl don't support dynamic tensor shape, + // and can be used for verification only) + ifm_index = inputs[0]; + axis_index = inputs[1]; + + // Each output should be interpreted as follow: + // [0, outputCount) -> An n-D tensor. + for (uint32_t n = 0; n < outputCount; ++n) + { + ofm_indexes.emplace_back(outputs[n]); + } +} + +} // namespace Split +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Split.h b/runtime/contrib/pure_arm_compute/src/internal/op/Split.h new file mode 100644 index 000000000..cb5f3eb2d --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Split.h @@ -0,0 +1,109 @@ +/* + * 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. + */ + +/** + * @file Split.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines Split node + */ + +#ifndef __INTERNAL_OP_SPLIT_H__ +#define __INTERNAL_OP_SPLIT_H__ + +#include "internal/op/Node.h" + +#include <cstdint> +#include <vector> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Split +{ + +/** + * @brief Struct to manipulate parameter for Split operation + */ +struct Param +{ + int32_t ifm_index; //!< index for input feature map + int32_t axis_index; //!< index for axis + + std::vector<int32_t> ofm_indexes; //!< index for output feature map + + /** + * @brief Default Constructor + */ + Param() = default; + /** + * @brief Construct a new Param object + * @param[in] inputCount the number of inputs + * @param[in] inputs pointer for input data + * @param[in] outputCount the number of outputs + * @param[in] outputs pointer for input data + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to define Split Operation + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new Split Node object + * @param param Parameter for Split Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Default Destructor + */ + virtual ~Node() = default; + +public: + /** + * @brief Get parameter + * @return Param reference + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Accept a NodeVisitor so that it can visit this node + * @param [in] v Visitor + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; //!< parameter for Split node +}; + +} // namespace Split +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_SPLIT_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/SquaredDifference.cc b/runtime/contrib/pure_arm_compute/src/internal/op/SquaredDifference.cc new file mode 100644 index 000000000..f6c8bc5df --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/SquaredDifference.cc @@ -0,0 +1,64 @@ +/* + * 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 "internal/op/SquaredDifference.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace SquaredDifference +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace SquaredDifference +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace SquaredDifference +{ +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 2 && outputCount == 1); + + ofm_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> LHS Tensor Index + // 1 -> RHS Tensor Index + lhs_index = inputs[0]; + rhs_index = inputs[1]; +} + +} // namespace SquaredDifference +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/SquaredDifference.h b/runtime/contrib/pure_arm_compute/src/internal/op/SquaredDifference.h new file mode 100644 index 000000000..ecbb03209 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/SquaredDifference.h @@ -0,0 +1,106 @@ +/* + * 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. + */ + +/** + * @file SquaredDifference.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines internal::tflite::op::SquaredDifference::Param struct + * and internal::tflite::op::SquaredDifference::Node class + */ +#ifndef __INTERNAL_OP_SQUAREDDIFFERENCE_H__ +#define __INTERNAL_OP_SQUAREDDIFFERENCE_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace SquaredDifference +{ + +/** + * @brief Struct to have indexes for operation parameter + */ +struct Param +{ + int32_t ofm_index; /**< Index of output feature map */ + + int32_t lhs_index; /**< Index of lhs */ + int32_t rhs_index; /**< Index of rhs */ + /** + * @brief Construct as default + */ + Param() = default; + /** + * @brief Construct a new Param object with params + * @param[in] inputCount Count of inputs + * @param[in] inputs Pointer of inputs + * @param[in] outputCount Count of outputs + * @param[in] outputs Pointer of outputs + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to represent an operation of data structure + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new Node object with param + * @param[in] param Param object that makes up a Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Destruct as default + */ + virtual ~Node() = default; + +public: + /** + * @brief Get a reference of Param object + * @return Reference of Param object + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Visit this Node by NodeVisitor + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace SquaredDifference +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_SQUAREDDIFFERENCE_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Squeeze.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Squeeze.cc new file mode 100644 index 000000000..6e89cd321 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Squeeze.cc @@ -0,0 +1,66 @@ +/* + * 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 "internal/op/Squeeze.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Squeeze +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace Squeeze +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Squeeze +{ +// dims_index is optional input +// if dims_index is not provided, dims_index is set to -1 +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 1 || inputCount == 2); + assert(outputCount == 1); + + output_index = outputs[0]; + + input_index = inputs[0]; + + // dims_index_optional = -1 by default + if (inputCount == 2) + dims_index_optional = inputs[1]; +} + +} // namespace Squeeze +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Squeeze.h b/runtime/contrib/pure_arm_compute/src/internal/op/Squeeze.h new file mode 100644 index 000000000..d5f36f85f --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Squeeze.h @@ -0,0 +1,108 @@ +/* + * 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. + */ + +/** + * @file Squeeze.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines internal::tflite::op::Squeeze::Param struct + * and internal::tflite::op::Squeeze::Node class + */ +#ifndef __INTERNAL_OP_SQUEEZE_H__ +#define __INTERNAL_OP_SQUEEZE_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Squeeze +{ + +/** + * @brief Struct to have indexes for operation parameter + */ +struct Param +{ + int32_t output_index; /**< Index of output feature map */ + + int32_t input_index; /**< Index of input feature map */ + // optional param. default is -1 + int32_t dims_index_optional = -1; /**< Index of dims */ + /** + * @brief Construct as default + */ + Param() = default; + /** + * @brief Construct a new Param object with params + * @param[in] inputCount Count of inputs + * @param[in] inputs Pointer of inputs + * @param[in] outputCount Count of outputs + * @param[in] outputs Pointer of outputs + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to represent an operation of data structure + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new Node object with param + * @param[in] param Param object that makes up a Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Destruct as default + */ + virtual ~Node() = default; + +public: + /** + * @brief Get a reference of Param object + * @return Reference of Param object + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Visit this Node by NodeVisitor + * @param[in] v Visitor + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace Squeeze +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_SQUEEZE_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/StridedSlice.cc b/runtime/contrib/pure_arm_compute/src/internal/op/StridedSlice.cc new file mode 100644 index 000000000..6e7958954 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/StridedSlice.cc @@ -0,0 +1,88 @@ +/* + * 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 "internal/op/StridedSlice.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace StridedSlice +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace StridedSlice +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace StridedSlice +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 7 && outputCount == 1); + + outputData_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> An n-D tensor, specifying the tensor to be sliced. + // 1 -> A 1-D Tensor of {@link ANEURALNETWORKS_TENSOR_INT32}, the starts of + // the dimensions of the input tensor to be sliced. The length must be + // of rank(input0). + // 2 -> A 1-D Tensor of {@link ANEURALNETWORKS_TENSOR_INT32}, the ends of + // the dimensions of the input tensor to be sliced. The length must be + // of rank(input0). + // 3 -> A 1-D Tensor of {@link ANEURALNETWORKS_TENSOR_INT32}, the strides of + // the dimensions of the input tensor to be sliced. The length must be + // of rank(input0). + // 4 -> An {@link ANEURALNETWORKS_INT32} scalar, begin_mask. If the ith bit + // of begin_mask is set, begin[i] is ignored and the fullest possible + // range in that dimension is used instead. + // 5 -> An {@link ANEURALNETWORKS_INT32} scalar, end_mask. If the ith bit of + // end_mask is set, end[i] is ignored and the fullest possible range in + // that dimension is used instead. + // 6 -> An {@link ANEURALNETWORKS_INT32} scalar, shrink_axis_mask. An int32 + // mask. If the ith bit of shrink_axis_mask is set, it implies that the + // ith specification shrinks the dimensionality by 1. A slice of size 1 + // starting from begin[i] in the dimension must be preserved. + inputData_index = inputs[0]; + startData_index = inputs[1]; + endData_index = inputs[2]; + stridesData_index = inputs[3]; + beginMask_index = inputs[4]; + endMask_index = inputs[5]; + shrinkAxisMask_index = inputs[6]; +} + +} // namespace StridedSlice +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/StridedSlice.h b/runtime/contrib/pure_arm_compute/src/internal/op/StridedSlice.h new file mode 100644 index 000000000..21dbb9e68 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/StridedSlice.h @@ -0,0 +1,113 @@ +/* + * 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. + */ + +/** + * @file StridedSlice.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines StridedSlice node + */ + +#ifndef __INTERNAL_OP_STRIDEDSLICE_H__ +#define __INTERNAL_OP_STRIDEDSLICE_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace StridedSlice +{ + +/** + * @brief Struct to manipulate parameter for StridedSlice operation + */ +struct Param +{ + int32_t outputData_index; //!< index for output data + + int32_t inputData_index; //!< index for input data + int32_t startData_index; //!< index where slicing start from + int32_t endData_index; //!< index where slicing ends to + int32_t stridesData_index; //!< index for stride value + int32_t beginMask_index; //!< index for beginmask + int32_t endMask_index; //!< index for endmask + int32_t shrinkAxisMask_index; //!< index for shrink axis + + /** + * @brief Default Constructor + */ + Param() = default; + /** + * @brief Construct a new Param object + * @param[in] inputCount the number of inputs + * @param[in] inputs pointer for input data + * @param[in] outputCount the number of outputs + * @param[in] outputs pointer for input data + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to define StridedSlice Operation + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new StridedSlice Node object + * @param param Parameter for StridedSlice Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Default Destructor + */ + virtual ~Node() = default; + +public: + /** + * @brief Get parameter + * @return Param reference + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Accept a NodeVisitor so that it can visit this node + * @param [in] v Visitor + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; //!< parameter for StridedSlice node +}; + +} // namespace StridedSlice +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_STRIDEDSLICE_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Sub.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Sub.cc new file mode 100644 index 000000000..74efe3c3a --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Sub.cc @@ -0,0 +1,67 @@ +/* + * 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 "internal/op/Sub.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Sub +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace Sub +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Sub +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 3 && outputCount == 1); + + ofm_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> LHS Tensor Index + // 1 -> RHS Tensor Index + // 2 -> Activation Index + lhs_index = inputs[0]; + rhs_index = inputs[1]; + activation_index = inputs[2]; +} + +} // namespace Sub +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Sub.h b/runtime/contrib/pure_arm_compute/src/internal/op/Sub.h new file mode 100644 index 000000000..864359d1e --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Sub.h @@ -0,0 +1,109 @@ +/* + * 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. + */ + +/** + * @file Sub.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines SUB Node + */ + +#ifndef __INTERNAL_OP_SUB_H__ +#define __INTERNAL_OP_SUB_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Sub +{ + +/** + * @brief Struct to manipulate parameters for SUB + */ +struct Param +{ + int32_t ofm_index; //!< index for output feature map + + int32_t lhs_index; //!< index for left-hand side + int32_t rhs_index; //!< index for right-hand side + int32_t activation_index; //!< index for activation function + + /** + * @brief Default Constructor + */ + Param() = default; + /** + * @brief Construct a new Param object + * @param[in] inputCount the number of inputs + * @param[in] inputs pointer for input data + * @param[in] outputCount the number of outputs + * @param[in] outputs pointer for input data + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to define SUB Operation + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new Sub Node object + * @param param Parameter for Sub Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Default Destructor + */ + virtual ~Node() = default; + +public: + /** + * @brief Get parameter + * @return Param reference + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Accept a NodeVisitor so that it can visit this node + * @param [in] v Visitor + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; //!< parameter for SUB node +}; + +} // namespace Sub +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_SUB_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Tanh.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Tanh.cc new file mode 100644 index 000000000..fbd72abe4 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Tanh.cc @@ -0,0 +1,63 @@ +/* + * 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 "internal/op/Tanh.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Tanh +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace Tanh +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Tanh +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 1 && outputCount == 1); + + ofm_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> Input Tensor Index + ifm_index = inputs[0]; +} + +} // namespace Tanh +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Tanh.h b/runtime/contrib/pure_arm_compute/src/internal/op/Tanh.h new file mode 100644 index 000000000..fd87297f1 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Tanh.h @@ -0,0 +1,107 @@ +/* + * 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. + */ + +/** + * @file Tanh.h + * @ingroup COM_AI_RUNTIME + * @brief This file defines TANH node + */ + +#ifndef __INTERNAL_OP_TANH_H__ +#define __INTERNAL_OP_TANH_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Tanh +{ + +/** + * @brief Struct to manipulate parameter for hyperbolic tangent operation + */ +struct Param +{ + int32_t ofm_index; //!< index for output feature map + + int32_t ifm_index; //!< index for input feature map + + /** + * @brief Default Constructor + */ + Param() = default; + /** + * @brief Construct a new Param object + * @param[in] inputCount the number of inputs + * @param[in] inputs pointer for input data + * @param[in] outputCount the number of outputs + * @param[in] outputs pointer for input data + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to define Tanh Operation + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new Tanh Node object + * @param param Parameter for Tanh Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Default Destructor + */ + virtual ~Node() = default; + +public: + /** + * @brief Get parameter + * @return Param reference + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Accept a NodeVisitor so that it can visit this node + * @param [in] v Visitor + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; //!< parameter for Tanh node +}; + +} // namespace Tanh +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_TANH_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/TopKV2.cc b/runtime/contrib/pure_arm_compute/src/internal/op/TopKV2.cc new file mode 100644 index 000000000..74d9a69d2 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/TopKV2.cc @@ -0,0 +1,70 @@ +/* + * 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 "internal/op/TopKV2.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace TopKV2 +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace TopKV2 +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace TopKV2 +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 2 && outputCount == 2); + + // Each input should be interpreted as follows: + // + // 0 -> Index for Output Values + // 1 -> Index for Output Indices + outputValues_index = outputs[0]; + outputIndices_index = outputs[1]; + + // Each input should be interpreted as follows: + // + // 0 -> Index for Input Data + // 1 -> Index for K + inputData_index = inputs[0]; + k_index = inputs[1]; +} + +} // namespace TopKV2 +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/TopKV2.h b/runtime/contrib/pure_arm_compute/src/internal/op/TopKV2.h new file mode 100644 index 000000000..02b7827e9 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/TopKV2.h @@ -0,0 +1,110 @@ +/* + * 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. + */ + +/** + * @file TopKV2.h + * @brief This file contains accept function and params for TopKV2 operation + * @ingroup COM_AI_RUNTIME + */ + +#ifndef __INTERNAL_OP_TOPKV2_H__ +#define __INTERNAL_OP_TOPKV2_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace TopKV2 +{ + +/** + * @brief Struct of TopKV2 operation's param + */ +struct Param +{ + int32_t outputValues_index; /**< Output values index */ + int32_t outputIndices_index; /**< Output indices index */ + + int32_t inputData_index; /**< Input data index */ + int32_t k_index; /**< K value index */ + + /** + * @brief Construct a new Param object for TopKV2 as default + */ + Param() = default; + + /** + * @brief Construct a new Param object for TopKV2 with params + * @param [in] inputCount The number of input + * @param [in] inputs Array containing inputs + * @param [in] outputCount The number of output + * @param [in] outputs Array containing outputs + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to define operation node for TopKV2 + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new Node object for TopKV2 with param + * @param [in] param Parameters for Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Destroy the Node object for TopKV2 + */ + virtual ~Node() = default; + +public: + /** + * @brief Get parameters for TopKV2 + * @return Parameters of TopKV2 + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Function for accepting node for TopKV2 + * @param [in] v Node visitor for invoking visit function of TopKV2 + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace TopKV2 +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_TOPKV2_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Transpose.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Transpose.cc new file mode 100644 index 000000000..0529e3790 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Transpose.cc @@ -0,0 +1,65 @@ +/* + * 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 "internal/op/Transpose.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Transpose +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace Transpose +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Transpose +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 2 && outputCount == 1); + + ofm_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> Input Tensor Index + // 1 -> Permutation Tensor Index + ifm_index = inputs[0]; + permu_index = inputs[1]; +} + +} // namespace Transpose +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Transpose.h b/runtime/contrib/pure_arm_compute/src/internal/op/Transpose.h new file mode 100644 index 000000000..bb01bf322 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Transpose.h @@ -0,0 +1,109 @@ +/* + * 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. + */ + +/** + * @file Transpose.h + * @brief This file contains accept function and params for Transpose operation + * @ingroup COM_AI_RUNTIME + */ + +#ifndef __INTERNAL_OP_TRANSPOSE_H__ +#define __INTERNAL_OP_TRANSPOSE_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Transpose +{ + +/** + * @brief Struct of Transpose operation's param + */ +struct Param +{ + int32_t ofm_index; /**< Output format index */ + + int32_t ifm_index; /**< Input format index */ + int32_t permu_index; /**< Permutation index */ + + /** + * @brief Construct a new Param object for Transpose as default + */ + Param() = default; + + /** + * @brief Construct a new Param object for Transpose with params + * @param [in] inputCount The number of input + * @param [in] inputs Array containing inputs + * @param [in] outputCount The number of output + * @param [in] outputs Array containing outputs + */ + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +/** + * @brief Class to define operation node for Transpose + */ +class Node final : public op::Node +{ +public: + /** + * @brief Construct a new Node object for Transpose with param + * @param [in] param Parameters for Node + */ + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + /** + * @brief Destroy the Node object for Transpose + */ + virtual ~Node() = default; + +public: + /** + * @brief Get parameters for Transpose + * @return Parameters of Transpose + */ + const Param ¶m(void) const { return _param; } + +public: + /** + * @brief Function for accepting node for Transpose + * @param [in] v Node visitor for invoking visit function of Transpose + * @return N/A + */ + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace Transpose +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_TRANSPOSE_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/TransposeConv.cc b/runtime/contrib/pure_arm_compute/src/internal/op/TransposeConv.cc new file mode 100644 index 000000000..502eff525 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/TransposeConv.cc @@ -0,0 +1,74 @@ +/* + * 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 "internal/op/TransposeConv.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace TransposeConv +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace TransposeConv +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace TransposeConv +{ + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 6 && outputCount == 1); + + ofm_index = outputs[0]; + + // Each input should be interpreted as follows: + // + // 0 -> Output Shape Index + // 1 -> Weights Index + // 2 -> Input Tensor Index + // 3 -> Padding Type + // 4 -> Stride width + // 5 -> Stride height + + op_shape_index = inputs[0]; + ker_index = inputs[1]; + ifm_index = inputs[2]; + padding_index = inputs[3]; + hstride_index = inputs[4]; + vstride_index = inputs[5]; +} + +} // namespace TransposeConv +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/TransposeConv.h b/runtime/contrib/pure_arm_compute/src/internal/op/TransposeConv.h new file mode 100644 index 000000000..b0122f82d --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/TransposeConv.h @@ -0,0 +1,74 @@ +/* + * 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 __INTERNAL_OP_TRANSPOSECONV_H__ +#define __INTERNAL_OP_TRANSPOSECONV_H__ + +#include "internal/op/Node.h" + +#include <cstdint> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace TransposeConv +{ + +struct Param +{ + int32_t ofm_index; + + int32_t op_shape_index; + int32_t ker_index; + int32_t ifm_index; + int32_t padding_index; + int32_t hstride_index; + int32_t vstride_index; + + Param() = default; + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +class Node final : public op::Node +{ +public: + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + virtual ~Node() = default; + +public: + const Param ¶m(void) const { return _param; } + +public: + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace TransposeConv +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_TRANSPOSECONV_H__ diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Unpack.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Unpack.cc new file mode 100644 index 000000000..a1be0280c --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Unpack.cc @@ -0,0 +1,68 @@ +/* + * 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 "internal/op/Unpack.h" +#include "internal/op/NodeVisitor.h" + +#include <cassert> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Unpack +{ + +void Node::accept(NodeVisitor &&v) const { v.visit(*this); } + +} // namespace Unpack +} // namespace op +} // namespace tflite +} // namespace internal + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Unpack +{ +// There are three inputs: tensor which is to be unpacked, +// axis along which tensor needs to be unpacked +// and number of splits along the axis. + +Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + assert(inputCount == 3); + + ifm_index = inputs[0]; + + for (uint32_t n = 0; n < outputCount; ++n) + { + ofm_indexes.emplace_back(outputs[n]); + } + num_split_index = inputs[1]; + axis_index = inputs[2]; +} + +} // namespace Unpack +} // namespace op +} // namespace tflite +} // namespace internal diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Unpack.h b/runtime/contrib/pure_arm_compute/src/internal/op/Unpack.h new file mode 100644 index 000000000..575e3d024 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/internal/op/Unpack.h @@ -0,0 +1,72 @@ +/* + * 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 __INTERNAL_OP_UNPACK_H__ +#define __INTERNAL_OP_UNPACK_H__ + +#include "internal/op/Node.h" + +#include <cstdint> +#include <vector> + +namespace internal +{ +namespace tflite +{ +namespace op +{ +namespace Unpack +{ + +struct Param +{ + int32_t ifm_index; + int32_t axis_index; + int32_t num_split_index; + // There are N outputs after Unpacking Input Tensor along axis + std::vector<int32_t> ofm_indexes; + + Param() = default; + Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs); +}; + +class Node final : public op::Node +{ +public: + Node(const Param ¶m) : _param(param) + { + // DO NOTHING + } + +public: + virtual ~Node() = default; + +public: + const Param ¶m(void) const { return _param; } + +public: + void accept(NodeVisitor &&) const override; + +private: + const Param _param; +}; + +} // namespace Unpack +} // namespace op +} // namespace tflite +} // namespace internal + +#endif // __INTERNAL_OP_UNPACK_H__ diff --git a/runtime/contrib/pure_arm_compute/src/library_info.cc b/runtime/contrib/pure_arm_compute/src/library_info.cc new file mode 100644 index 000000000..02a616094 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/library_info.cc @@ -0,0 +1,17 @@ +/* + * 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. + */ + +volatile static const char info[] = "library information : runtime=pure_arm_compute"; diff --git a/runtime/contrib/pure_arm_compute/src/logging.h b/runtime/contrib/pure_arm_compute/src/logging.h new file mode 100644 index 000000000..447da03e2 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/logging.h @@ -0,0 +1,74 @@ +/* + * 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. + */ + +/** + * @file logging.h + * @brief This file contains Context class for logging. + * @ingroup COM_AI_RUNTIME + */ + +#ifndef __PURE_ARM_COMPUTE_LOGGING_H__ +#define __PURE_ARM_COMPUTE_LOGGING_H__ + +#include <iostream> + +namespace logging +{ + +/** + * @brief class to define Context for logging + */ +class Context +{ +public: + /** + * @brief Construct default + */ + Context() : _enabled{false} + { + auto env = std::getenv("PURE_ARM_COMPUTE_LOG_ENABLE"); + + if (env && std::strtol(env, NULL, 0) > 0) + { + _enabled = true; + } + } + +public: + /** + * @brief Get @c true if PURE_ARM_COMPUTE_LOG_ENABLE has been set as environment value, otherwise + * @c false + * @return @c true if PURE_ARM_COMPUTE_LOG_ENABLE has been set as environment value, otherwise @c + * false + */ + bool enabled(void) const { return _enabled; } + +private: + bool _enabled; +}; + +/** + * @brief static Context class for logging + */ +static Context ctx; + +} // namespace logging + +#define VERBOSE(name) \ + if (::logging::ctx.enabled()) \ + std::cout << "[" << #name << "] " + +#endif // __PURE_ARM_COMPUTE_LOGGING_H__ diff --git a/runtime/contrib/pure_arm_compute/src/memory.cc b/runtime/contrib/pure_arm_compute/src/memory.cc new file mode 100644 index 000000000..9e999661a --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/memory.cc @@ -0,0 +1,55 @@ +/* + * 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 <NeuralNetworks.h> +#include <sys/mman.h> +#include <memory> + +#include "cpp14/memory.h" +#include "memory.h" + +int ANeuralNetworksMemory_createFromFd(size_t size, int protect, int fd, size_t offset, + ANeuralNetworksMemory **memory) +{ + if (memory == nullptr) + { + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + // Use unique pointer to avoid memory leak + std::unique_ptr<ANeuralNetworksMemory> memory_ptr = + nnfw::cpp14::make_unique<ANeuralNetworksMemory>(size, protect, fd, offset); + if (memory_ptr == nullptr) + { + return ANEURALNETWORKS_OUT_OF_MEMORY; + } + *memory = memory_ptr.release(); + + return ANEURALNETWORKS_NO_ERROR; +} + +void ANeuralNetworksMemory_free(ANeuralNetworksMemory *memory) { delete memory; } + +// +// ANeuralNetworksMemory +// +ANeuralNetworksMemory::ANeuralNetworksMemory(size_t size, int protect, int fd, size_t offset) +{ + _base = reinterpret_cast<uint8_t *>(mmap(nullptr, size, protect, MAP_PRIVATE, fd, offset)); + _size = size; +} + +ANeuralNetworksMemory::~ANeuralNetworksMemory() { munmap(reinterpret_cast<void *>(_base), _size); } diff --git a/runtime/contrib/pure_arm_compute/src/memory.h b/runtime/contrib/pure_arm_compute/src/memory.h new file mode 100644 index 000000000..ffac26ef6 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/memory.h @@ -0,0 +1,69 @@ +/* + * 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. + */ + +/** + * @file execution.h + * @brief This file defines ANeuralNetworksMemory class for handling Memory NNAPI + * @ingroup COM_AI_RUNTIME + */ + +#ifndef __MEMORY_H__ +#define __MEMORY_H__ + +#include <cstdint> + +/** + * @brief struct to define Memory NNAPI + */ +struct ANeuralNetworksMemory +{ +public: + /** + * @brief Constructor with params + * @param [in] size The requested size in bytes + * @param [in] protect The desired memory protection for the mapping + * @param [in] fd The requested file descriptor + * @param [in] offset The offset to the beginning of the file of the area to map + */ + ANeuralNetworksMemory(size_t size, int protect, int fd, size_t offset); + /** + * @brief Destructor default + */ + ~ANeuralNetworksMemory(); + +public: + /** + * @brief Get size + * @return size + */ + size_t size(void) const { return _size; } + /** + * @brief Get base pointer + * @return base pointer + */ + uint8_t *base(void) { return _base; } + /** + * @brief Get base pointer + * @return const base pointer + */ + const uint8_t *base(void) const { return _base; } + +private: + size_t _size; + uint8_t *_base; +}; + +#endif // __MEMORY_H__ diff --git a/runtime/contrib/pure_arm_compute/src/model.cc b/runtime/contrib/pure_arm_compute/src/model.cc new file mode 100644 index 000000000..ddca589db --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/model.cc @@ -0,0 +1,1082 @@ +/* + * 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 <NeuralNetworks.h> +#include <NeuralNetworksEx.h> + +#include <cassert> +#include <stdexcept> + +#include "model.h" +#include "memory.h" + +int ANeuralNetworksModel_create(ANeuralNetworksModel **model) +{ + if (model == nullptr) + { + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + ANeuralNetworksModel *model_ptr = new ANeuralNetworksModel{}; + + if (model_ptr == nullptr) + { + return ANEURALNETWORKS_OUT_OF_MEMORY; + } + + *model = model_ptr; + + return ANEURALNETWORKS_NO_ERROR; +} + +void ANeuralNetworksModel_free(ANeuralNetworksModel *model) { delete model; } + +int ANeuralNetworksModel_addOperand(ANeuralNetworksModel *model, + const ANeuralNetworksOperandType *type) +{ + if ((model == nullptr) || (type == nullptr)) + { + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + if (model->isFinished()) + { + return ANEURALNETWORKS_BAD_STATE; + } + + if (type->type == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) + { + // Quantized: + // scale: a 32 bit floating point value greater than zero + // zeroPoint: a 32 bit integer, in range [0, 255] + if (type->scale <= 0.0f) + { + return ANEURALNETWORKS_BAD_DATA; + } + + if (type->zeroPoint < 0 || type->zeroPoint > 255) + { + return ANEURALNETWORKS_BAD_DATA; + } + } + // NOTE Validation of scale and zeroPoint would be skipped for a while. + // We do not know whether scalar type can have scale and zeroPoint. + // To pass ValidationTest and GeneratedTest, this validation code + // would not be implemented until we can define this issue clearly. + // + // scale and zeroPoint should be zero for scalars and non-fixed point tensors + // else if ((type->scale != 0.0f) || (type->zeroPoint != 0)) + // { + // return ANEURALNETWORKS_BAD_DATA; + // } + + // scalar is ANEURALNETWORKS_FLOAT32, ANEURALNETWORKS_INT32 or ANEURALNETWORKS_UINT32. + // ANEURALNETWORKS_TENSOR_FLOAT32, ANEURALNETWORKS_TENSOR_INT32 and + // ANEURALNETWORKS_TENSOR_QUANT8_ASYMM are not scalar + // + // dimensionCount should be zero for scalars + if (type->dimensionCount != 0 && + (type->type == ANEURALNETWORKS_FLOAT32 || type->type == ANEURALNETWORKS_INT32 || + type->type == ANEURALNETWORKS_UINT32)) + { + return ANEURALNETWORKS_BAD_DATA; + } + + // ASSUME A tensor operand should consists of fp32 or int32 values. + // NOTE We do not care about scala operands. + assert((type->dimensionCount == 0) || (type->type == ANEURALNETWORKS_TENSOR_FLOAT32 || + type->type == ANEURALNETWORKS_TENSOR_INT32 || + type->type == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM)); + + internal::tflite::operand::Shape shape(type->dimensionCount); + + for (uint32_t axis = 0; axis < type->dimensionCount; ++axis) + { + shape.dim(axis) = type->dimensions[axis]; + } + + model->deref().operands().append(shape, type->type, type->scale, type->zeroPoint); + + // NOTE We do NOT allocate CLTensor here as we do not how to interpret this one. + // TensorFlow Lite may interpret a rank-4 tensor either as a feature map (with batch) or + // a convolution kernel. + + return ANEURALNETWORKS_NO_ERROR; +} + +int ANeuralNetworksModel_setOperandValue(ANeuralNetworksModel *model, int32_t index, + const void *buffer, size_t length) +{ + if ((model == nullptr) || ((buffer == nullptr) && (length != 0))) + { + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + const internal::tflite::operand::Index ind{index}; + auto &obj = model->deref().operands().at(ind); + + if (buffer == nullptr) + { + using internal::tflite::operand::ExternalData; + obj.data<ExternalData>(reinterpret_cast<const uint8_t *>(buffer), length); + } + else + { + using internal::tflite::operand::CachedData; + obj.data<CachedData>(reinterpret_cast<const uint8_t *>(buffer), length); + } + + return ANEURALNETWORKS_NO_ERROR; +} + +int ANeuralNetworksModel_setOperandValueFromMemory(ANeuralNetworksModel *model, int32_t index, + const ANeuralNetworksMemory *memory, + size_t offset, size_t length) +{ + if ((model == nullptr) || (memory == nullptr)) + { + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + const internal::tflite::operand::Index ind{index}; + auto &obj = model->deref().operands().at(ind); + + using internal::tflite::operand::ExternalData; + + obj.data<ExternalData>(reinterpret_cast<const uint8_t *>(memory->base() + offset), length); + + return ANEURALNETWORKS_NO_ERROR; +} + +int ANeuralNetworksModel_addOperation(ANeuralNetworksModel *model, + ANeuralNetworksOperationType type, uint32_t inputCount, + const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + if (model == nullptr || inputs == nullptr || outputs == nullptr) + { + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + if (model->isFinished()) + { + return ANEURALNETWORKS_BAD_STATE; + } + + if (type < ANEURALNETWORKS_ADD || type > ANEURALNETWORKS_TRANSPOSE) + { + return ANEURALNETWORKS_BAD_DATA; + } + + switch (type) + { + case ANEURALNETWORKS_ADD: + { + assert(inputCount == 3); + assert(outputCount == 1); + + using internal::tflite::op::Add::Param; + using internal::tflite::op::Add::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_SUB: + { + assert(inputCount == 3); + assert(outputCount == 1); + + using internal::tflite::op::Sub::Param; + using internal::tflite::op::Sub::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_MUL: + { + assert(inputCount == 3); + assert(outputCount == 1); + + using internal::tflite::op::Mul::Param; + using internal::tflite::op::Mul::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_DIV: + { + assert(inputCount == 3); + assert(outputCount == 1); + + using internal::tflite::op::Div::Param; + using internal::tflite::op::Div::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_CONV_2D: + { + // inputCount is either 7 or 10 acccording to NN API specification. + // - Padding is implicit when inputCount is 7 + // - Padding is explicit when inputCount is 10 + assert(inputCount == 7 || inputCount == 10); + assert(outputCount == 1); + + if (inputCount == 7) + { + using internal::tflite::op::Conv2D::Implicit::Param; + using internal::tflite::op::Conv2D::Implicit::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + } + else + { + using internal::tflite::op::Conv2D::Explicit::Param; + using internal::tflite::op::Conv2D::Explicit::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + } + + break; + } + case ANEURALNETWORKS_DEPTHWISE_CONV_2D: + { + // inputCount is either 8 or 11 acccording to NN API specification. + // - Padding is implicit when inputCount is 8 + // - Padding is explicit when inputCount is 11 + assert(inputCount == 8 || inputCount == 11); + assert(outputCount == 1); + + if (inputCount == 8) + { + using internal::tflite::op::DepthwiseConv2D::Implicit::Param; + using internal::tflite::op::DepthwiseConv2D::Implicit::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + } + else + { + using internal::tflite::op::DepthwiseConv2D::Explicit::Param; + using internal::tflite::op::DepthwiseConv2D::Explicit::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + } + + break; + } + case ANEURALNETWORKS_MAX_POOL_2D: + { + // inputCount is either 7 or 10 acccording to NN API specification. + // - Padding is implicit when inputCount is 7 + // - Padding is explicit when inputCount is 10 + assert(inputCount == 7 || inputCount == 10); + assert(outputCount == 1); + + if (inputCount == 7) + { + using internal::tflite::op::MaxPool2D::Implicit::Param; + using internal::tflite::op::MaxPool2D::Implicit::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + } + else + { + using internal::tflite::op::MaxPool2D::Explicit::Param; + using internal::tflite::op::MaxPool2D::Explicit::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + } + + break; + } + case ANEURALNETWORKS_DEQUANTIZE: + { + assert(outputCount == 1 && inputCount == 1); + using internal::tflite::op::Dequantize::Param; + using internal::tflite::op::Dequantize::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_AVERAGE_POOL_2D: + { + // inputCount is either 7 or 10 acccording to NN API specification. + // - Padding is implicit when inputCount is 7 + // - Padding is explicit when inputCount is 10 + assert(inputCount == 7 || inputCount == 10); + assert(outputCount == 1); + + if (inputCount == 7) + { + using internal::tflite::op::AvgPool2D::Implicit::Param; + using internal::tflite::op::AvgPool2D::Implicit::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + } + else + { + using internal::tflite::op::AvgPool2D::Explicit::Param; + using internal::tflite::op::AvgPool2D::Explicit::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + } + + break; + } + case ANEURALNETWORKS_CONCATENATION: + { + using internal::tflite::op::Concat::Param; + using internal::tflite::op::Concat::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_RESIZE_BILINEAR: + { + using internal::tflite::op::ResizeBilinear::Param; + using internal::tflite::op::ResizeBilinear::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_RESHAPE: + { + using internal::tflite::op::Reshape::Param; + using internal::tflite::op::Reshape::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_SQUEEZE: + { + using internal::tflite::op::Squeeze::Param; + using internal::tflite::op::Squeeze::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_FULLY_CONNECTED: + { + using internal::tflite::op::FullyConnected::Param; + using internal::tflite::op::FullyConnected::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_SOFTMAX: + { + using internal::tflite::op::Softmax::Param; + using internal::tflite::op::Softmax::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_RELU: + { + using internal::tflite::op::ReLU::Param; + using internal::tflite::op::ReLU::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_RELU1: + { + using internal::tflite::op::ReLU1::Param; + using internal::tflite::op::ReLU1::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_RELU6: + { + using internal::tflite::op::ReLU6::Param; + using internal::tflite::op::ReLU6::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_TANH: + { + using internal::tflite::op::Tanh::Param; + using internal::tflite::op::Tanh::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_STRIDED_SLICE: + { + using internal::tflite::op::StridedSlice::Param; + using internal::tflite::op::StridedSlice::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_LOGISTIC: + { + using internal::tflite::op::Logistic::Param; + using internal::tflite::op::Logistic::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_MEAN: + { + using internal::tflite::op::Mean::Param; + using internal::tflite::op::Mean::Node; + + auto &operations = model->deref().operations(); + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_RNN: + { + using internal::tflite::op::RNN::Param; + using internal::tflite::op::RNN::Node; + + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_TRANSPOSE: + { + using internal::tflite::op::Transpose::Param; + using internal::tflite::op::Transpose::Node; + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_LSTM: + { + using internal::tflite::op::LSTM::Param; + using internal::tflite::op::LSTM::Node; + + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_FLOOR: + { + using internal::tflite::op::Floor::Param; + using internal::tflite::op::Floor::Node; + + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_PAD: + { + assert(inputCount == 2 && outputCount == 1); + + using internal::tflite::op::Pad::Param; + using internal::tflite::op::Pad::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_SPACE_TO_DEPTH: + { + using internal::tflite::op::SpaceToDepth::Param; + using internal::tflite::op::SpaceToDepth::Node; + + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_SPACE_TO_BATCH_ND: + { + using internal::tflite::op::SpaceToBatchND::Param; + using internal::tflite::op::SpaceToBatchND::Node; + + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_BATCH_TO_SPACE_ND: + { + using internal::tflite::op::BatchToSpaceNd::Param; + using internal::tflite::op::BatchToSpaceNd::Node; + + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_L2_POOL_2D: + { + // Input count is 7 for Implicit Padding + // Input count is 10 for Explicit Padding + assert(inputCount == 7 || inputCount == 10); + assert(outputCount == 1); + + if (inputCount == 7) + { + using internal::tflite::op::L2Pool2D::Implicit::Param; + using internal::tflite::op::L2Pool2D::Implicit::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + } + else + { + using internal::tflite::op::L2Pool2D::Explicit::Param; + using internal::tflite::op::L2Pool2D::Explicit::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + } + + break; + } + case ANEURALNETWORKS_EMBEDDING_LOOKUP: + { + assert(inputCount == 2); + assert(outputCount == 1); + + using internal::tflite::op::EmbeddingLookup::Param; + using internal::tflite::op::EmbeddingLookup::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_L2_NORMALIZATION: + { + assert(inputCount == 1 && outputCount == 1); + + using internal::tflite::op::L2Normalization::Param; + using internal::tflite::op::L2Normalization::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_HASHTABLE_LOOKUP: + { + assert(inputCount == 3); + assert(outputCount == 2); + + using internal::tflite::op::HashtableLookup::Param; + using internal::tflite::op::HashtableLookup::Node; + + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_LOCAL_RESPONSE_NORMALIZATION: + { + + using internal::tflite::op::LocalResponseNormalization::Param; + using internal::tflite::op::LocalResponseNormalization::Node; + + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_DEPTH_TO_SPACE: + { + using internal::tflite::op::DepthToSpace::Param; + using internal::tflite::op::DepthToSpace::Node; + + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + default: + throw std::runtime_error{"Not supported operation"}; + }; + + return ANEURALNETWORKS_NO_ERROR; +} + +int ANeuralNetworksModel_addOperationEx(ANeuralNetworksModel *model, + ANeuralNetworksOperationTypeEx type, uint32_t inputCount, + const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + if ((model == nullptr) || (inputs == nullptr) || (outputs == nullptr)) + { + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + switch (type) + { + case ANEURALNETWORKS_CAST_EX: + { + using internal::tflite::op::Cast::Param; + using internal::tflite::op::Cast::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_REDUCE_MIN_EX: + { + using internal::tflite::op::ReduceMin::Param; + using internal::tflite::op::ReduceMin::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_REDUCE_MAX_EX: + { + using internal::tflite::op::ReduceMax::Param; + using internal::tflite::op::ReduceMax::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_PRELU_EX: + { + using internal::tflite::op::PReLU::Param; + using internal::tflite::op::PReLU::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_TRANSPOSE_CONV_EX: + { + using internal::tflite::op::TransposeConv::Param; + using internal::tflite::op::TransposeConv::Node; + + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_LOGICAL_AND_EX: + { + using internal::tflite::op::LogicalAnd::Param; + using internal::tflite::op::LogicalAnd::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_LOGICAL_OR_EX: + { + using internal::tflite::op::LogicalOr::Param; + using internal::tflite::op::LogicalOr::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_LOGICAL_NOT_EX: + { + using internal::tflite::op::LogicalNot::Param; + using internal::tflite::op::LogicalNot::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_RSQRT_EX: + { + using internal::tflite::op::RSQRT::Param; + using internal::tflite::op::RSQRT::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_SQRT_EX: + { + using internal::tflite::op::SQRT::Param; + using internal::tflite::op::SQRT::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_EQUAL_EX: + { + using internal::tflite::op::Equal::Param; + using internal::tflite::op::Equal::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_SQUARED_DIFFERENCE_EX: + { + using internal::tflite::op::SquaredDifference::Param; + using internal::tflite::op::SquaredDifference::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_TOPK_V2_EX: + { + using internal::tflite::op::TopKV2::Param; + using internal::tflite::op::TopKV2::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_GATHER_EX: + { + using internal::tflite::op::Gather::Param; + using internal::tflite::op::Gather::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_SPLIT_EX: + { + using internal::tflite::op::Split::Param; + using internal::tflite::op::Split::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_UNPACK_EX: + { + using internal::tflite::op::Unpack::Param; + using internal::tflite::op::Unpack::Node; + + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_NEG_EX: + { + using internal::tflite::op::Neg::Param; + using internal::tflite::op::Neg::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_EXP_EX: + { + using internal::tflite::op::Exp::Param; + using internal::tflite::op::Exp::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_REDUCE_SUM_EX: + { + using internal::tflite::op::ReduceSum::Param; + using internal::tflite::op::ReduceSum::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_PACK_EX: + { + using internal::tflite::op::Pack::Param; + using internal::tflite::op::Pack::Node; + + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_ABS_EX: + { + using internal::tflite::op::Abs::Param; + using internal::tflite::op::Abs::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_ARGMAX_EX: + { + using internal::tflite::op::ArgMax::Param; + using internal::tflite::op::ArgMax::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + case ANEURALNETWORKS_NOT_EQUAL_EX: + { + using internal::tflite::op::NotEqual::Param; + using internal::tflite::op::NotEqual::Node; + + // Add 'operations' + auto &operations = model->deref().operations(); + + operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs}); + + break; + } + + default: + throw std::runtime_error{"Not supported operation"}; + } + + return ANEURALNETWORKS_NO_ERROR; +} + +int ANeuralNetworksModel_identifyInputsAndOutputs(ANeuralNetworksModel *model, uint32_t inputCount, + const uint32_t *inputs, uint32_t outputCount, + const uint32_t *outputs) +{ + if ((model == nullptr) || (inputs == nullptr) || (outputs == nullptr)) + { + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + if (model->isFinished()) + { + return ANEURALNETWORKS_BAD_STATE; + } + + // NOTE ::internal::tflite::operand::Index uses int as its underlying type as various NNAPI + // functions such as ANeuralNetworksModel_setOperandValue use int to represent operand index + // + // ANeuralNetworksModel_identifyInputsAndOutputs, however, uses uint32_t to represent operand + // index. + // + // Below, static_cast<int>(...) is introduced to eliminate compiler warning. + for (uint32_t n = 0; n < inputCount; ++n) + { + const ::internal::tflite::operand::Index ind{static_cast<int>(inputs[n])}; + model->deref().inputs.emplace_back(ind); + } + + for (uint32_t n = 0; n < outputCount; ++n) + { + const ::internal::tflite::operand::Index ind{static_cast<int>(outputs[n])}; + model->deref().outputs.emplace_back(ind); + } + + return ANEURALNETWORKS_NO_ERROR; +} + +int ANeuralNetworksModel_finish(ANeuralNetworksModel *model) +{ + if (model == nullptr) + { + return ANEURALNETWORKS_UNEXPECTED_NULL; + } + + if (model->isFinished()) + { + return ANEURALNETWORKS_BAD_STATE; + } + + model->markAsFinished(); + + return ANEURALNETWORKS_NO_ERROR; +} + +// +// ANeuralNetworksModel +// +ANeuralNetworksModel::ANeuralNetworksModel() : _model{new internal::tflite::Model} +{ + // DO NOTHING +} diff --git a/runtime/contrib/pure_arm_compute/src/model.h b/runtime/contrib/pure_arm_compute/src/model.h new file mode 100644 index 000000000..8acc894f4 --- /dev/null +++ b/runtime/contrib/pure_arm_compute/src/model.h @@ -0,0 +1,70 @@ +/* + * 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. + */ + +/** + * @file model.h + * @brief This file contains ANeuralNetworksModel classe for handling Model NNAPI such as + * ANeuralNetworksModel_create, ANeuralNetworksModel_addOperand + * @ingroup COM_AI_RUNTIME + */ + +#ifndef __MODEL_H__ +#define __MODEL_H__ + +#include "internal/Model.h" + +/** + * @brief struct to express Model of NNAPI + */ +struct ANeuralNetworksModel +{ +public: + /** + * @brief Construct without params + */ + ANeuralNetworksModel(); + +public: + /** + * @brief Get reference of internal::tflite::Model + * @return Reference of internal::tflite::Model + */ + internal::tflite::Model &deref(void) { return *_model; } + +public: + /** + * @brief Release internal::tflite::Model pointer to param + * @param [in] model To get released internal::tflite::Model pointer + * @return N/A + */ + void release(std::shared_ptr<const internal::tflite::Model> &model) { model = _model; } + /** + * @brief Get @c true if ANeuralNetworksModel_finish has been called, otherwise @c false + * @return @c true if ANeuralNetworksModel_finish has been called, otherwise @c false + */ + bool isFinished() { return _isFinished == true; } + /** + * @brief Mark model process finished + * @return N/A + */ + void markAsFinished() { _isFinished = true; } + +private: + std::shared_ptr<internal::tflite::Model> _model; + bool _isFinished{false}; +}; + +#endif // __MODEL_H__ |