diff options
Diffstat (limited to 'compiler/luci-interpreter/src/loader')
98 files changed, 4758 insertions, 637 deletions
diff --git a/compiler/luci-interpreter/src/loader/CMakeLists.txt b/compiler/luci-interpreter/src/loader/CMakeLists.txt index d99485d06..292771592 100644 --- a/compiler/luci-interpreter/src/loader/CMakeLists.txt +++ b/compiler/luci-interpreter/src/loader/CMakeLists.txt @@ -1,22 +1,39 @@ -nnas_find_package(GTest REQUIRED) - set(SOURCES GraphLoader.h GraphLoader.cpp + KernelBuilderHelper.h + KernelBuilderHelper.cpp KernelBuilder.h KernelBuilder.cpp ModuleLoader.h ModuleLoader.cpp - RuntimeToIR.h) + RuntimeToIR.h + nodes/Builders.h) + +# include kernel specific builders +macro(REGISTER_KERNEL NODE) + list(APPEND SOURCES "nodes/${NODE}.cpp") +endmacro(REGISTER_KERNEL) +include(${KERNEL_REGISTER_FILE}) + +add_library(${LUCI_INTERPRETER_LOADER} STATIC ${SOURCES}) +if (NOT NNCC_LIBRARY_NO_PIC) + set_target_properties(${LUCI_INTERPRETER_LOADER} PROPERTIES POSITION_INDEPENDENT_CODE ON) +endif(NOT NNCC_LIBRARY_NO_PIC) +target_include_directories(${LUCI_INTERPRETER_LOADER} PUBLIC "${LUCI_INTERPRETER_PAL_DIR}") +target_include_directories(${LUCI_INTERPRETER_LOADER} PUBLIC "${LUCI_INTERPRETER_SOURCE_DIR}") -add_library(luci_interpreter_loader STATIC ${SOURCES}) -set_target_properties(luci_interpreter_loader PROPERTIES POSITION_INDEPENDENT_CODE ON) -target_include_directories(luci_interpreter_loader PUBLIC "${LUCI_INTERPRETER_SOURCE_DIR}") -target_link_libraries(luci_interpreter_loader - PUBLIC luci_lang luci_interpreter_core - PRIVATE luci_interpreter_kernels nncc_common) +target_link_libraries(${LUCI_INTERPRETER_LOADER} + PUBLIC luci_lang ${LUCI_INTERPRETER_CORE} + PRIVATE ${LUCI_INTERPRETER_KERNELS} nncc_common luci_plan) + +if(NOT ENABLE_TEST) + return() +endif(NOT ENABLE_TEST) + +nnas_find_package(GTest REQUIRED) set(TEST_SOURCES KernelBuilder.test.cpp) -GTest_AddTest(luci_interpreter_loader_test ${TEST_SOURCES}) -target_link_libraries(luci_interpreter_loader_test luci_interpreter_loader) +GTest_AddTest(${LUCI_INTERPRETER_LOADER}_test ${TEST_SOURCES}) +target_link_libraries(${LUCI_INTERPRETER_LOADER}_test ${LUCI_INTERPRETER_LOADER}) diff --git a/compiler/luci-interpreter/src/loader/GraphLoader.cpp b/compiler/luci-interpreter/src/loader/GraphLoader.cpp index 95c654769..ba99a579b 100644 --- a/compiler/luci-interpreter/src/loader/GraphLoader.cpp +++ b/compiler/luci-interpreter/src/loader/GraphLoader.cpp @@ -18,6 +18,7 @@ #include "loader/KernelBuilder.h" +#include <luci/Plan/CircleNodeExecutionPlan.h> #include <loco/IR/Algorithm.h> namespace luci_interpreter @@ -57,13 +58,41 @@ const void *getNodeData(const luci::CircleConst *node, size_t *data_size) return getNodeDataImpl<DataType::U8>(node, data_size); case DataType::FLOAT32: return getNodeDataImpl<DataType::FLOAT32>(node, data_size); + case DataType::S8: + return getNodeDataImpl<DataType::S8>(node, data_size); + case DataType::S16: + return getNodeDataImpl<DataType::S16>(node, data_size); case DataType::S32: return getNodeDataImpl<DataType::S32>(node, data_size); + case DataType::S64: + return getNodeDataImpl<DataType::S64>(node, data_size); + case DataType::BOOL: + return getNodeDataImpl<DataType::BOOL>(node, data_size); default: throw std::runtime_error("Unsupported type."); } } +const void *getNodeData(const luci::CircleCustom *node, size_t *data_size) +{ + if (node->custom_code() != "CircleReferencingConst") + return nullptr; + + // helper struct which describes data loaded to custom_options of CircleReferencingConst node + // TODO move this struct to header + struct ConstDataReference + { + const uint8_t *data = nullptr; + uint32_t size = 0; + }; + + const auto &custom_options = node->custom_options(); + const auto &const_data_ref = *reinterpret_cast<const ConstDataReference *>(custom_options.data()); + + *data_size = const_data_ref.size; + return const_data_ref.data; +} + bool isExecutableNode(const luci::CircleNode *node) { switch (node->opcode()) @@ -74,10 +103,30 @@ bool isExecutableNode(const luci::CircleNode *node) case luci::CircleOpcode::CIRCLEOUTPUT: case luci::CircleOpcode::CIRCLEOUTPUTEXCLUDE: // The following nodes denote outputs of multiple-output nodes. + case luci::CircleOpcode::CIRCLEBIDIRECTIONAL_SEQUENCE_LSTM_OUT: + case luci::CircleOpcode::CIRCLECUSTOMOUT: case luci::CircleOpcode::CIRCLEIFOUT: + case luci::CircleOpcode::CIRCLENONMAXSUPPRESSIONV4OUT: + case luci::CircleOpcode::CIRCLENONMAXSUPPRESSIONV5OUT: case luci::CircleOpcode::CIRCLESPLITOUT: + case luci::CircleOpcode::CIRCLESPLITVOUT: + case luci::CircleOpcode::CIRCLETOPKV2OUT: + case luci::CircleOpcode::CIRCLEUNIQUEOUT: case luci::CircleOpcode::CIRCLEUNPACKOUT: + case luci::CircleOpcode::CIRCLEVARIABLE: + case luci::CircleOpcode::CIRCLEWHILEOUT: return false; + // Custom nodes may be executable and non-executable + case luci::CircleOpcode::CUSTOM: + { + auto const custom_node = loco::must_cast<const luci::CircleCustom *>(node); + + // TODO handle more non-executable Custom ops here + if (custom_node->custom_code() == "CircleReferencingConst") + return false; + + return true; + } default: return true; } @@ -91,23 +140,43 @@ bool isTensorProducingNode(const luci::CircleNode *node) case luci::CircleOpcode::CIRCLEOUTPUT: // The following nodes are multiple-output nodes. They do not produce tensors, the tensors // are produced by the corresponding *Out nodes instead. + case luci::CircleOpcode::BIDIRECTIONAL_SEQUENCE_LSTM: + case luci::CircleOpcode::CUSTOM: case luci::CircleOpcode::IF: + case luci::CircleOpcode::NON_MAX_SUPPRESSION_V4: + case luci::CircleOpcode::NON_MAX_SUPPRESSION_V5: case luci::CircleOpcode::SPLIT: + case luci::CircleOpcode::SPLIT_V: + case luci::CircleOpcode::TOPK_V2: + case luci::CircleOpcode::UNIQUE: case luci::CircleOpcode::UNPACK: + case luci::CircleOpcode::WHILE: return false; default: return true; } } +bool isSupportedCustomNode(const luci::CircleNode *node) +{ + const auto custom_node = loco::must_cast<const luci::CircleCustom *>(node); + + // TODO handle more Custom ops here + if (custom_node->custom_code() == "CircleReferencingConst") + return true; + + return false; +} + } // namespace GraphLoader::GraphLoader( - const loco::Graph *graph, RuntimeGraph *runtime_graph, RuntimeToIR &runtime_to_ir, - const std::unordered_map<const loco::Graph *, RuntimeGraph *> &graph_to_runtime_graph, - std::unordered_map<const loco::Node *, Tensor *> &node_to_tensor) - : _graph(graph), _runtime_graph(runtime_graph), _runtime_to_ir(runtime_to_ir), - _graph_to_runtime_graph(graph_to_runtime_graph), _node_to_tensor(node_to_tensor) + const loco::Graph *graph, RuntimeGraph *runtime_graph, RuntimeToIR &runtime_to_ir, + const std::unordered_map<const loco::Graph *, RuntimeGraph *> &graph_to_runtime_graph, + std::unordered_map<const loco::Node *, Tensor *> &node_to_tensor, IMemoryManager *memory_manager) + : _graph(graph), _runtime_graph(runtime_graph), _runtime_to_ir(runtime_to_ir), + _graph_to_runtime_graph(graph_to_runtime_graph), _node_to_tensor(node_to_tensor), + _memory_manager(memory_manager) { } @@ -117,24 +186,36 @@ void GraphLoader::loadTensors() { const auto *node = loco::must_cast<const luci::CircleNode *>(_graph->nodes()->at(i)); + if (node->opcode() == luci::CircleOpcode::CUSTOM && !isSupportedCustomNode(node)) + { + const auto *cnode = loco::must_cast<const luci::CircleCustom *>(node); + throw std::runtime_error("Unsupported Custom operator. " + cnode->custom_code() + " in " + + node->name()); + } + if (!isTensorProducingNode(node)) continue; - // Only Input and Const nodes have shapes. Shapes of intermediate tensors will be inferred. + // Only Input, Const, Custom and Variable nodes have shapes. Shapes of intermediate tensors will + // be inferred. Shape shape{}; - if (const auto *input_node = dynamic_cast<const luci::CircleInput *>(node)) + switch (node->opcode()) { - shape = getNodeShape(input_node); - } - else if (const auto *const_node = dynamic_cast<const luci::CircleConst *>(node)) - { - shape = getNodeShape(const_node); + case luci::CircleOpcode::CIRCLECONST: + case luci::CircleOpcode::CIRCLECUSTOMOUT: + case luci::CircleOpcode::CIRCLEINPUT: + case luci::CircleOpcode::CIRCLEVARIABLE: + shape = getNodeShape(node); + break; + default: + break; } AffineQuantization quantization; if (node->quantparam() != nullptr) { const luci::CircleQuantParam *params = node->quantparam(); + assert(params->scale.size() == params->zerop.size()); quantization.scale.assign(params->scale.cbegin(), params->scale.cend()); quantization.zero_point.assign(params->zerop.cbegin(), params->zerop.cend()); quantization.quantized_dimension = params->quantized_dimension; @@ -143,12 +224,40 @@ void GraphLoader::loadTensors() auto tensor = std::make_unique<Tensor>(node->dtype(), std::move(shape), std::move(quantization), node->name()); + // If node has execution plan then read memory offsets for nodes + // from the beginning of shared memory buffer. Used in Static Memory Manager. + if (luci::has_execution_plan(node)) + { + auto execution_plan = luci::get_execution_plan(node); + assert(!execution_plan.offsets().empty()); + tensor->set_offset(execution_plan.offsets().front()); + } + if (const auto *const_node = dynamic_cast<const luci::CircleConst *>(node)) { size_t data_size{}; const void *const_data = getNodeData(const_node, &data_size); if (const_data != nullptr) + { + _memory_manager->allocate_memory(*tensor); tensor->writeData(const_data, data_size); + } + } + else if (const auto *custom_out_node = dynamic_cast<const luci::CircleCustomOut *>(node)) + { + const auto *custom_node = + loco::must_cast<const luci::CircleCustom *>(custom_out_node->input()); + + if (custom_node->custom_code() == "CircleReferencingConst") + { + size_t data_size{}; + const void *const_data = getNodeData(custom_node, &data_size); + if (const_data != nullptr) + { + _memory_manager->allocate_memory(*tensor); + tensor->writeData(const_data, data_size); + } + } } _node_to_tensor.emplace(node, tensor.get()); @@ -165,6 +274,7 @@ void GraphLoader::initInputOutputTensors() const for (size_t i = 0; i < input_nodes.size(); ++i) { input_tensors[i] = _node_to_tensor.at(input_nodes[i]); + _memory_manager->allocate_memory(*input_tensors[i]); } _runtime_graph->setInputTensors(input_tensors); @@ -183,16 +293,54 @@ void GraphLoader::loadOperators() KernelBuilder kernel_builder(_graph_to_runtime_graph, _node_to_tensor); // Create kernels for executable nodes. This has to be done in execution order. - for (const loco::Node *loco_node : - loco::postorder_traversal(loco::output_nodes(const_cast<loco::Graph *>(_graph)))) + auto graph = const_cast<loco::Graph *>(_graph); + + auto const graph_nodes = loco::all_nodes(graph); + + // Checking for execution plan in node annotations. + bool has_execution_annotation = true; + auto const checking_exec_plan = [&has_execution_annotation](auto const node) { + const auto *circle_node = loco::must_cast<const luci::CircleNode *>(node); + if (!luci::has_execution_plan(circle_node)) + has_execution_annotation = false; + }; + std::for_each(begin(graph_nodes), end(graph_nodes), checking_exec_plan); + + if (has_execution_annotation) { - const auto *node = loco::must_cast<const luci::CircleNode *>(loco_node); + // Build ordered_nodes vector that stores the order of execution of graph nodes. + std::vector<const luci::CircleNode *> ordered_nodes(graph_nodes.size()); + + auto const filler = [&ordered_nodes](auto const node) { + const auto *circle_node = loco::must_cast<const luci::CircleNode *>(node); + auto const position = luci::get_execution_plan(circle_node).order_in_plan(); + ordered_nodes.at(position) = circle_node; + }; + std::for_each(begin(graph_nodes), end(graph_nodes), filler); - if (isExecutableNode(node)) + for (auto node : ordered_nodes) + { + if (isExecutableNode(node)) + { + std::unique_ptr<Kernel> kernel = kernel_builder.build(node); + _runtime_to_ir.kernel_to_node.emplace(kernel.get(), node); + _runtime_graph->addKernel(std::move(kernel)); + } + } + } + else + { + // If it is impossible to build the execution order plan, + // then we use the default postorder_traversal approach. + for (const loco::Node *loco_node : loco::postorder_traversal(loco::output_nodes(graph))) { - std::unique_ptr<Kernel> kernel = node->accept(&kernel_builder); - _runtime_to_ir.kernel_to_node.emplace(kernel.get(), node); - _runtime_graph->addKernel(std::move(kernel)); + const auto *node = loco::must_cast<const luci::CircleNode *>(loco_node); + if (isExecutableNode(node)) + { + std::unique_ptr<Kernel> kernel = kernel_builder.build(node); + _runtime_to_ir.kernel_to_node.emplace(kernel.get(), node); + _runtime_graph->addKernel(std::move(kernel)); + } } } } diff --git a/compiler/luci-interpreter/src/loader/GraphLoader.h b/compiler/luci-interpreter/src/loader/GraphLoader.h index 89c5bcad7..fe066ecf8 100644 --- a/compiler/luci-interpreter/src/loader/GraphLoader.h +++ b/compiler/luci-interpreter/src/loader/GraphLoader.h @@ -19,6 +19,7 @@ #include "core/RuntimeGraph.h" #include "loader/RuntimeToIR.h" +#include "luci_interpreter/MemoryManager.h" #include <loco/IR/Graph.h> @@ -32,7 +33,8 @@ class GraphLoader public: GraphLoader(const loco::Graph *graph, RuntimeGraph *runtime_graph, RuntimeToIR &runtime_to_ir, const std::unordered_map<const loco::Graph *, RuntimeGraph *> &graph_to_runtime_graph, - std::unordered_map<const loco::Node *, Tensor *> &node_to_tensor); + std::unordered_map<const loco::Node *, Tensor *> &node_to_tensor, + IMemoryManager *memory_manager); void loadTensors(); void initInputOutputTensors() const; @@ -42,6 +44,7 @@ private: const loco::Graph *_graph; RuntimeGraph *_runtime_graph; RuntimeToIR &_runtime_to_ir; + IMemoryManager *_memory_manager; const std::unordered_map<const loco::Graph *, RuntimeGraph *> &_graph_to_runtime_graph; std::unordered_map<const loco::Node *, Tensor *> &_node_to_tensor; diff --git a/compiler/luci-interpreter/src/loader/KernelBuilder.cpp b/compiler/luci-interpreter/src/loader/KernelBuilder.cpp index 126a1cb5b..c1e2c630a 100644 --- a/compiler/luci-interpreter/src/loader/KernelBuilder.cpp +++ b/compiler/luci-interpreter/src/loader/KernelBuilder.cpp @@ -15,586 +15,118 @@ */ #include "loader/KernelBuilder.h" +#include "loader/nodes/Builders.h" -#include "kernels/Add.h" -#include "kernels/ArgMax.h" -#include "kernels/AveragePool2D.h" -#include "kernels/Concatenation.h" -#include "kernels/Conv2D.h" -#include "kernels/DepthToSpace.h" -#include "kernels/DepthwiseConv2D.h" -#include "kernels/Elu.h" -#include "kernels/FullyConnected.h" -#include "kernels/If.h" -#include "kernels/L2Normalize.h" -#include "kernels/L2Pool2D.h" -#include "kernels/LeakyRelu.h" -#include "kernels/LocalResponseNormalization.h" -#include "kernels/Logistic.h" -#include "kernels/MaxPool2D.h" -#include "kernels/Mean.h" -#include "kernels/Mul.h" -#include "kernels/Pad.h" -#include "kernels/Reshape.h" -#include "kernels/Reverse.h" -#include "kernels/Rsqrt.h" -#include "kernels/Slice.h" -#include "kernels/Softmax.h" -#include "kernels/SpaceToDepth.h" -#include "kernels/Split.h" -#include "kernels/StridedSlice.h" -#include "kernels/Sqrt.h" -#include "kernels/Squeeze.h" -#include "kernels/Tanh.h" -#include "kernels/Unpack.h" -#include "kernels/Transpose.h" -#include "kernels/TransposeConv.h" +#include <luci/IR/CircleOpcode.h> +#include <luci/IR/CircleNodeDecl.h> #include <stdexcept> -namespace luci_interpreter -{ - -template <typename CircleNodeOut> -static std::vector<const loco::Node *> collectOutputNodes(const luci::CircleNode *node) +namespace { - std::vector<const CircleNodeOut *> output_nodes; - for (const loco::Node *loco_node : loco::succs(node)) - { - output_nodes.push_back(loco::must_cast<const CircleNodeOut *>(loco_node)); - } - std::sort(output_nodes.begin(), output_nodes.end(), - [](const CircleNodeOut *node1, const CircleNodeOut *node2) { - return node1->index() < node2->index(); - }); - return {output_nodes.cbegin(), output_nodes.cend()}; -} -const Tensor *KernelBuilder::getInputTensor(const loco::Node *node) const +// TODO Extract this helper function +const std::string toString(luci::CircleOpcode opcode) { - const Tensor *tensor = _node_to_tensor.at(node); - assert(tensor != nullptr); - return tensor; -} + static const char *names[] = { +#define CIRCLE_NODE(OPCODE, CIRCLE_CLASS) #CIRCLE_CLASS, +#define CIRCLE_VNODE(OPCODE, CIRCLE_CLASS) #CIRCLE_CLASS, +#include <luci/IR/CircleNodes.lst> +#undef CIRCLE_NODE +#undef CIRCLE_VNODE + }; -const Tensor *KernelBuilder::getOptionalInputTensor(const loco::Node *node) const -{ - if (dynamic_cast<const luci::CircleOutputExclude *>(node)) - { - return nullptr; - } - return getInputTensor(node); -} + auto const node_name = names[static_cast<int>(opcode)]; -Tensor *KernelBuilder::getOutputTensor(const loco::Node *node) const -{ - Tensor *tensor = _node_to_tensor.at(node); - assert(tensor != nullptr); - return tensor; -} + assert(std::string(node_name).substr(0, 6) == "Circle"); // FIX_ME_UNLESS -std::vector<Tensor *> -KernelBuilder::getOutputTensors(const std::vector<const loco::Node *> &nodes) const -{ - std::vector<Tensor *> tensors; - tensors.reserve(nodes.size()); - for (const loco::Node *node : nodes) - tensors.push_back(getOutputTensor(node)); - return tensors; + // Return substring of class name ("Circle" is sliced out) + // Ex: Return "Conv2D" for "CircleConv2D" node + return std::string(node_name).substr(6); } -RuntimeGraph *KernelBuilder::getRuntimeGraph(const loco::Graph *graph) const -{ - RuntimeGraph *runtime_graph = _graph_to_runtime_graph.at(graph); - assert(runtime_graph != nullptr); - return runtime_graph; -} +} // namespace -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleAdd *node) +namespace luci_interpreter { - assert(node->arity() == 2); - - const Tensor *input1 = getInputTensor(node->x()); - const Tensor *input2 = getInputTensor(node->y()); - Tensor *output = getOutputTensor(node); - AddParams params{}; - params.activation = node->fusedActivationFunction(); +#define CIRCLE_NODE(OPCODE, CLASS) CLASS, +#define CIRCLE_VNODE(OPCODE, CLASS) CLASS, - return std::make_unique<kernels::Add>(input1, input2, output, params); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleArgMax *node) +// This enum is auxiliary. +// It is duplicate of luci::CircleOpcode but initialized with CLASS instead of OPCODE, +// because list of target operators is in format of CLASS names +enum class BuilderId { - assert(node->arity() == 2); - const Tensor *input = getInputTensor(node->input()); - const Tensor *axis = getInputTensor(node->dimension()); - Tensor *output = getOutputTensor(node); +#include <luci/IR/CircleNodes.lst> + Size // casts to count of values in BuilderId enum +}; - ArgMaxParams params{}; - params.output_type = node->output_type(); +#undef CIRCLE_VNODE +#undef CIRCLE_NODE - return std::make_unique<kernels::ArgMax>(input, axis, output, params); -} +/** + * @brief Registry of kernel builders + * + * This class contains mapping from Opcodes to kernel builder functions + */ -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleAveragePool2D *node) +class KernelBuilderRegistry { - assert(node->arity() == 1); +public: + using KernelBuilderFunc = std::unique_ptr<Kernel>(const luci::CircleNode *, + KernelBuilderHelper &); - const Tensor *input = getInputTensor(node->value()); - Tensor *output = getOutputTensor(node); + KernelBuilderRegistry() : _operator_builders(size_t(BuilderId::Size), nullptr) + { +#define REGISTER_KERNEL(name) \ + register_kernel_builder(BuilderId::Circle##name, build_kernel_Circle##name); - Pool2DParams params{}; - params.padding = node->padding(); - params.filter_height = node->filter()->h(); - params.filter_width = node->filter()->w(); - params.stride_height = node->stride()->h(); - params.stride_width = node->stride()->w(); - params.activation = node->fusedActivationFunction(); +#include "KernelsToBuild.lst" - return std::make_unique<kernels::AveragePool2D>(input, output, params); -} +#undef REGISTER_KERNEL + } -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleConcatenation *node) -{ - std::vector<const Tensor *> inputs(node->numValues()); - for (uint32_t i = 0; i < node->numValues(); ++i) + KernelBuilderFunc *get_kernel_builder_func(luci::CircleOpcode opcode) const { - inputs[i] = getInputTensor(node->values(i)); + return _operator_builders.at(size_t(opcode)); } - Tensor *output = getOutputTensor(node); - - ConcatenationParams params{}; - params.axis = node->axis(); - - return std::make_unique<kernels::Concatenation>(std::move(inputs), output, params); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleConst *) -{ - throw std::runtime_error("Const node cannot be executed."); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleConv2D *node) -{ - assert(node->arity() == 3); - - const Tensor *input = getInputTensor(node->input()); - const Tensor *filter = getInputTensor(node->filter()); - const Tensor *bias = getInputTensor(node->bias()); - Tensor *output = getOutputTensor(node); - - Conv2DParams params{}; - params.padding = node->padding(); - params.stride_height = node->stride()->h(); - params.stride_width = node->stride()->w(); - params.dilation_height_factor = node->dilation()->h(); - params.dilation_width_factor = node->dilation()->w(); - params.activation = node->fusedActivationFunction(); - - return std::make_unique<kernels::Conv2D>(input, filter, bias, output, params); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleDepthToSpace *node) -{ - assert(node->arity() == 1); - - const Tensor *input = getInputTensor(node->input()); - Tensor *output = getOutputTensor(node); - - DepthToSpaceParams params{}; - params.block_size = node->block_size(); - - return std::make_unique<kernels::DepthToSpace>(input, output, params); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleDepthwiseConv2D *node) -{ - assert(node->arity() == 3); - - const Tensor *input = getInputTensor(node->input()); - const Tensor *filter = getInputTensor(node->filter()); - const Tensor *bias = getInputTensor(node->bias()); - Tensor *output = getOutputTensor(node); - DepthwiseConv2DParams params{}; - params.padding = node->padding(); - params.depth_multiplier = node->depthMultiplier(); - params.stride_height = node->stride()->h(); - params.stride_width = node->stride()->w(); - params.dilation_height_factor = node->dilation()->h(); - params.dilation_width_factor = node->dilation()->w(); - params.activation = node->fusedActivationFunction(); +private: + std::vector<KernelBuilderFunc *> _operator_builders; - return std::make_unique<kernels::DepthwiseConv2D>(input, filter, bias, output, params); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleElu *node) -{ - assert(node->arity() == 1); - - const Tensor *input = getInputTensor(node->features()); - Tensor *output = getOutputTensor(node); - - return std::make_unique<kernels::Elu>(input, output); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleFullyConnected *node) -{ - assert(node->arity() == 3); - - const Tensor *input = getInputTensor(node->input()); - const Tensor *weights = getInputTensor(node->weights()); - const Tensor *bias = getOptionalInputTensor(node->bias()); - Tensor *output = getOutputTensor(node); - - FullyConnectedParams params{}; - params.activation = node->fusedActivationFunction(); - - return std::make_unique<kernels::FullyConnected>(input, weights, bias, output, params); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleIf *node) -{ - auto output_nodes = collectOutputNodes<luci::CircleIfOut>(node); - assert(node->arity() == 1 + node->input_count()); - assert(output_nodes.size() == static_cast<size_t>(node->output_count())); - - const Tensor *cond = getInputTensor(node->cond()); - std::vector<const Tensor *> inputs(node->input_count()); - for (uint32_t i = 0; i < node->input_count(); ++i) + void register_kernel_builder(BuilderId id, KernelBuilderFunc *func) { - inputs[i] = getInputTensor(node->input(i)); + // Using BuilderId is a duplicate of luci::CirclreOpcode, + // size_t(id) is equal to size_t(corresponding operation opcode). + assert(size_t(id) < _operator_builders.size()); + _operator_builders[size_t(id)] = func; } - std::vector<Tensor *> outputs = getOutputTensors(output_nodes); - - RuntimeGraph *then_graph = getRuntimeGraph(node->then_graph()); - RuntimeGraph *else_graph = getRuntimeGraph(node->else_graph()); - - return std::make_unique<kernels::If>(cond, std::move(inputs), std::move(outputs), then_graph, - else_graph); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleInput *) -{ - throw std::runtime_error("Input node cannot be executed."); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleL2Normalize *node) -{ - assert(node->arity() == 1); - - const Tensor *input = getInputTensor(node->x()); - Tensor *output = getOutputTensor(node); +}; - L2NormParams params{}; - params.activation = node->fusedActivationFunction(); - - return std::make_unique<kernels::L2Normalize>(input, output, params); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleL2Pool2D *node) -{ - assert(node->arity() == 1); - - const Tensor *input = getInputTensor(node->value()); - Tensor *output = getOutputTensor(node); - - Pool2DParams params{}; - params.padding = node->padding(); - params.filter_height = node->filter()->h(); - params.filter_width = node->filter()->w(); - params.stride_height = node->stride()->h(); - params.stride_width = node->stride()->w(); - params.activation = node->fusedActivationFunction(); - - return std::make_unique<kernels::L2Pool2D>(input, output, params); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleLeakyRelu *node) -{ - assert(node->arity() == 1); - const Tensor *input = getInputTensor(node->features()); - Tensor *output = getOutputTensor(node); - - LeakyReluParams params{}; - params.alpha = node->alpha(); - - return std::make_unique<kernels::LeakyRelu>(input, output, params); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleLocalResponseNormalization *node) -{ - assert(node->arity() == 1); - const Tensor *input = getInputTensor(node->input()); - Tensor *output = getOutputTensor(node); - - LocalResponseNormalizationParams params{}; - params.radius = node->radius(); - params.bias = node->bias(); - params.alpha = node->alpha(); - params.beta = node->beta(); - - return std::make_unique<kernels::LocalResponseNormalization>(input, output, params); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleLogistic *node) +KernelBuilder::KernelBuilder( + const std::unordered_map<const loco::Graph *, RuntimeGraph *> &graph_to_runtime_graph, + const std::unordered_map<const loco::Node *, Tensor *> &node_to_tensor) + : KernelBuilderHelper(graph_to_runtime_graph, node_to_tensor) { - assert(node->arity() == 1); - - const Tensor *input = getInputTensor(node->x()); - Tensor *output = getOutputTensor(node); - - return std::make_unique<kernels::Logistic>(input, output); + _builder_registry = std::make_unique<KernelBuilderRegistry>(); } -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleMaxPool2D *node) +KernelBuilder::~KernelBuilder() { - assert(node->arity() == 1); - - const Tensor *input = getInputTensor(node->value()); - Tensor *output = getOutputTensor(node); - - Pool2DParams params{}; - params.padding = node->padding(); - params.filter_height = node->filter()->h(); - params.filter_width = node->filter()->w(); - params.stride_height = node->stride()->h(); - params.stride_width = node->stride()->w(); - params.activation = node->fusedActivationFunction(); - - return std::make_unique<kernels::MaxPool2D>(input, output, params); + // Need to define in this CPP to hide KernelBuilderRegistry internals. + // This destructor deletes _builder_registry } -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleMean *node) +std::unique_ptr<Kernel> KernelBuilder::build(const luci::CircleNode *node) { - assert(node->arity() == 2); - - const Tensor *input = getInputTensor(node->input()); - const Tensor *axes = getInputTensor(node->reduction_indices()); - Tensor *output = getOutputTensor(node); - - ReducerParams params{}; - params.keep_dims = node->keep_dims(); - - return std::make_unique<kernels::Mean>(input, axes, output, params); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleMul *node) -{ - assert(node->arity() == 2); - - const Tensor *input1 = getInputTensor(node->x()); - const Tensor *input2 = getInputTensor(node->y()); - Tensor *output = getOutputTensor(node); - - MulParams params{}; - params.activation = node->fusedActivationFunction(); - - return std::make_unique<kernels::Mul>(input1, input2, output, params); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleOutput *) -{ - throw std::runtime_error("Output node cannot be executed."); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CirclePad *node) -{ - assert(node->arity() == 2); - - const Tensor *input = getInputTensor(node->input()); - const Tensor *paddings = getInputTensor(node->paddings()); - Tensor *output = getOutputTensor(node); - - return std::make_unique<kernels::Pad>(input, paddings, output); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleReshape *node) -{ - assert(node->arity() == 2); - - const Tensor *input = getInputTensor(node->tensor()); - const Tensor *shape = getInputTensor(node->shape()); - Tensor *output = getOutputTensor(node); - - // NOTE 'newShape' attribute is ignored. - return std::make_unique<kernels::Reshape>(input, shape, output); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleReverseV2 *node) -{ - assert(node->arity() == 2); - - const Tensor *input = getInputTensor(node->tensor()); - const Tensor *axes = getInputTensor(node->axis()); - Tensor *output = getOutputTensor(node); - - return std::make_unique<kernels::Reverse>(input, axes, output); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleRsqrt *node) -{ - assert(node->arity() == 1); - - const Tensor *input = getInputTensor(node->x()); - Tensor *output = getOutputTensor(node); - - return std::make_unique<kernels::Rsqrt>(input, output); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleSlice *node) -{ - assert(node->arity() == 3); - - const Tensor *input = getInputTensor(node->input()); - const Tensor *begin = getInputTensor(node->begin()); - const Tensor *size = getInputTensor(node->size()); - - Tensor *output = getOutputTensor(node); - - return std::make_unique<kernels::Slice>(input, begin, size, output); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleSoftmax *node) -{ - assert(node->arity() == 1); - - const Tensor *input = getInputTensor(node->logits()); - Tensor *output = getOutputTensor(node); - - SoftmaxParams params{}; - params.beta = node->beta(); - - return std::make_unique<kernels::Softmax>(input, output, params); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleSpaceToDepth *node) -{ - assert(node->arity() == 1); - const Tensor *input = getInputTensor(node->input()); - - Tensor *output = getOutputTensor(node); - - SpaceToDepthParams params{}; - params.block_size = node->block_size(); - - return std::make_unique<kernels::SpaceToDepth>(input, output, params); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleSplit *node) -{ - auto output_nodes = collectOutputNodes<luci::CircleSplitOut>(node); - assert(node->arity() == 2); - assert(output_nodes.size() == static_cast<size_t>(node->num_split())); - - const Tensor *axis = getInputTensor(node->split_dim()); - const Tensor *input = getInputTensor(node->input()); - std::vector<Tensor *> outputs = getOutputTensors(output_nodes); - - // NOTE 'num_splits' attribute is ignored. - return std::make_unique<kernels::Split>(axis, input, std::move(outputs)); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleSqrt *node) -{ - assert(node->arity() == 1); - - const Tensor *input = getInputTensor(node->x()); - Tensor *output = getOutputTensor(node); - - return std::make_unique<kernels::Sqrt>(input, output); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleSqueeze *node) -{ - assert(node->arity() == 1); - - const Tensor *input = getInputTensor(node->input()); - Tensor *output = getOutputTensor(node); - - SqueezeParams params{}; - params.squeeze_dims = node->squeeze_dims(); - - return std::make_unique<kernels::Squeeze>(input, output, params); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleStridedSlice *node) -{ - assert(node->arity() == 4); - - const Tensor *input = getInputTensor(node->input()); - const Tensor *begin = getInputTensor(node->begin()); - const Tensor *end = getInputTensor(node->end()); - const Tensor *strides = getInputTensor(node->strides()); - - Tensor *output = getOutputTensor(node); - - StridedSliceParams params{}; - params.begin_mask = node->begin_mask(); - params.ellipsis_mask = node->ellipsis_mask(); - params.end_mask = node->end_mask(); - params.new_axis_mask = node->new_axis_mask(); - params.shrink_axis_mask = node->shrink_axis_mask(); - - return std::make_unique<kernels::StridedSlice>(input, begin, end, strides, output, params); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleTanh *node) -{ - assert(node->arity() == 1); - - const Tensor *input = getInputTensor(node->x()); - Tensor *output = getOutputTensor(node); - - return std::make_unique<kernels::Tanh>(input, output); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleTranspose *node) -{ - assert(node->arity() == 2); - - const Tensor *input = getInputTensor(node->a()); - const Tensor *perm = getInputTensor(node->perm()); - Tensor *output = getOutputTensor(node); - - return std::make_unique<kernels::Transpose>(input, perm, output); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleTransposeConv *node) -{ - assert(node->arity() == 4); - - const Tensor *input_sizes = getInputTensor(node->inputSizes()); - const Tensor *filter = getInputTensor(node->filter()); - const Tensor *out_backprop = getInputTensor(node->outBackprop()); - const Tensor *bias = getOptionalInputTensor(node->bias()); - - Tensor *output = getOutputTensor(node); - - TransposeConvParams params{}; - params.padding = node->padding(); - params.stride_height = node->stride()->h(); - params.stride_width = node->stride()->w(); - - return std::make_unique<kernels::TransposeConv>(input_sizes, filter, out_backprop, bias, output, - params); -} - -std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleUnpack *node) -{ - auto output_nodes = collectOutputNodes<luci::CircleUnpackOut>(node); - assert(node->arity() == 1); - assert(output_nodes.size() == static_cast<size_t>(node->num())); - - const Tensor *input = getInputTensor(node->value()); - std::vector<Tensor *> outputs = getOutputTensors(output_nodes); - - UnpackParams params{}; - params.axis = node->axis(); + auto specific_builder = _builder_registry->get_kernel_builder_func(node->opcode()); + if (specific_builder != nullptr) + return specific_builder(node, *this); - // NOTE 'num' attribute is ignored. - return std::make_unique<kernels::Unpack>(input, std::move(outputs), params); + std::string msg = "Unsupported operator: "; + msg += toString(node->opcode()) + " in " + std::string(node->name()); + throw std::invalid_argument(msg.c_str()); } } // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/KernelBuilder.h b/compiler/luci-interpreter/src/loader/KernelBuilder.h index 31cb9d8fc..b1f383394 100644 --- a/compiler/luci-interpreter/src/loader/KernelBuilder.h +++ b/compiler/luci-interpreter/src/loader/KernelBuilder.h @@ -17,79 +17,34 @@ #ifndef LUCI_INTERPRETER_LOADER_KERNELBUILDER_H #define LUCI_INTERPRETER_LOADER_KERNELBUILDER_H +#include "loader/KernelBuilderHelper.h" + #include "core/Kernel.h" #include "core/RuntimeGraph.h" #include <luci/IR/CircleNodeVisitor.h> #include <memory> -#include <vector> #include <unordered_map> namespace luci_interpreter { -class KernelBuilder : public luci::CircleNodeVisitor<std::unique_ptr<Kernel>> +class KernelBuilderRegistry; + +class KernelBuilder : public KernelBuilderHelper { public: KernelBuilder( - const std::unordered_map<const loco::Graph *, RuntimeGraph *> &graph_to_runtime_graph, - const std::unordered_map<const loco::Node *, Tensor *> &node_to_tensor) - : _graph_to_runtime_graph(graph_to_runtime_graph), _node_to_tensor(node_to_tensor) - { - } - - std::unique_ptr<Kernel> visit(const luci::CircleAdd *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleArgMax *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleAveragePool2D *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleConcatenation *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleConv2D *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleConst *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleDepthToSpace *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleDepthwiseConv2D *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleElu *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleFullyConnected *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleIf *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleL2Normalize *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleL2Pool2D *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleLeakyRelu *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleLocalResponseNormalization *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleLogistic *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleInput *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleMaxPool2D *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleMean *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleMul *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleOutput *node) override; - std::unique_ptr<Kernel> visit(const luci::CirclePad *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleReshape *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleReverseV2 *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleRsqrt *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleSlice *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleSoftmax *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleSpaceToDepth *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleSplit *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleStridedSlice *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleSqrt *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleSqueeze *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleTanh *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleTranspose *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleTransposeConv *node) override; - std::unique_ptr<Kernel> visit(const luci::CircleUnpack *node) override; - -private: - const Tensor *getInputTensor(const loco::Node *node) const; - - const Tensor *getOptionalInputTensor(const loco::Node *node) const; - - Tensor *getOutputTensor(const loco::Node *node) const; + const std::unordered_map<const loco::Graph *, RuntimeGraph *> &graph_to_runtime_graph, + const std::unordered_map<const loco::Node *, Tensor *> &node_to_tensor); - std::vector<Tensor *> getOutputTensors(const std::vector<const loco::Node *> &nodes) const; + ~KernelBuilder(); - RuntimeGraph *getRuntimeGraph(const loco::Graph *graph) const; + std::unique_ptr<Kernel> build(const luci::CircleNode *node); private: - const std::unordered_map<const loco::Graph *, RuntimeGraph *> &_graph_to_runtime_graph; - const std::unordered_map<const loco::Node *, Tensor *> &_node_to_tensor; + std::unique_ptr<KernelBuilderRegistry> _builder_registry; }; } // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/KernelBuilder.test.cpp b/compiler/luci-interpreter/src/loader/KernelBuilder.test.cpp index 4e2bc3d0b..10a01f418 100644 --- a/compiler/luci-interpreter/src/loader/KernelBuilder.test.cpp +++ b/compiler/luci-interpreter/src/loader/KernelBuilder.test.cpp @@ -16,35 +16,67 @@ #include "loader/GraphLoader.h" #include "loader/KernelBuilder.h" +#include "luci_interpreter/SimpleMemoryManager.h" #include <kernels/Add.h> #include <kernels/ArgMax.h> #include <kernels/AveragePool2D.h> +#include <kernels/BatchMatMul.h> +#include <kernels/Cast.h> #include <kernels/Concatenation.h> #include <kernels/Conv2D.h> #include <kernels/DepthToSpace.h> #include <kernels/DepthwiseConv2D.h> +#include <kernels/Div.h> #include <kernels/Elu.h> +#include <kernels/Exp.h> +#include <kernels/Floor.h> +#include <kernels/FloorDiv.h> +#include <kernels/Equal.h> #include <kernels/FullyConnected.h> +#include <kernels/Greater.h> +#include <kernels/GreaterEqual.h> +#include <kernels/InstanceNorm.h> #include <kernels/L2Normalize.h> #include <kernels/L2Pool2D.h> #include <kernels/LeakyRelu.h> +#include <kernels/Less.h> +#include <kernels/LessEqual.h> #include <kernels/LocalResponseNormalization.h> +#include <kernels/LogicalAnd.h> +#include <kernels/LogicalNot.h> +#include <kernels/LogicalOr.h> #include <kernels/Logistic.h> +#include <kernels/LogSoftmax.h> +#include <kernels/Maximum.h> #include <kernels/MaxPool2D.h> #include <kernels/Mean.h> +#include <kernels/Minimum.h> #include <kernels/Mul.h> +#include <kernels/Neg.h> +#include <kernels/NotEqual.h> +#include <kernels/OneHot.h> #include <kernels/Pad.h> +#include <kernels/PadV2.h> +#include <kernels/Pow.h> +#include <kernels/PRelu.h> +#include <kernels/Relu.h> +#include <kernels/Relu6.h> #include <kernels/Reshape.h> -#include <kernels/Reverse.h> +#include <kernels/ResizeBilinear.h> +#include <kernels/ResizeNearestNeighbor.h> +#include <kernels/ReverseV2.h> #include <kernels/Rsqrt.h> #include <kernels/Slice.h> #include <kernels/Softmax.h> #include <kernels/SpaceToDepth.h> #include <kernels/Split.h> +#include <kernels/SplitV.h> #include <kernels/Sqrt.h> +#include <kernels/SquaredDifference.h> #include <kernels/Squeeze.h> #include <kernels/StridedSlice.h> +#include <kernels/Sub.h> #include <kernels/Tanh.h> #include <kernels/Transpose.h> #include <kernels/TransposeConv.h> @@ -63,6 +95,9 @@ class KernelBuilderTest : public Test { protected: luci::CircleInput *createInputNode() { return createNode<luci::CircleInput>(); } + void SetUp() override { _memory_manager = std::make_unique<SimpleMemoryManager>(); } + + std::unique_ptr<IMemoryManager> _memory_manager; template <typename NodeT, typename... Args> NodeT *createNode(Args &&... args) { @@ -86,15 +121,16 @@ protected: { std::unordered_map<const loco::Graph *, RuntimeGraph *> graph_to_runtime_graph; - RuntimeGraph runtime_graph(nullptr); + RuntimeGraph runtime_graph(nullptr, _memory_manager.get()); + graph_to_runtime_graph[&_graph] = &runtime_graph; RuntimeToIR runtime_to_ir; GraphLoader graph_loader(&_graph, &runtime_graph, runtime_to_ir, graph_to_runtime_graph, - _node_to_tensor); + _node_to_tensor, _memory_manager.get()); graph_loader.loadTensors(); KernelBuilder kernel_builder(graph_to_runtime_graph, _node_to_tensor); - auto kernel = op->accept(&kernel_builder); + auto kernel = kernel_builder.build(op); return std::unique_ptr<KernelT>(dynamic_cast<KernelT *>(kernel.release())); } @@ -175,6 +211,41 @@ TEST_F(KernelBuilderTest, AveragePool2D) EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction())); } +TEST_F(KernelBuilderTest, BatchMatMul) +{ + auto *lhs = createInputNode(); + auto *rhs = createInputNode(); + + auto *op = createNode<luci::CircleBatchMatMul>(); + op->x(lhs); + op->y(rhs); + op->adj_x(false); + op->adj_y(false); + + auto kernel = buildKernel<kernels::BatchMatMul>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->x(), lhs); + checkTensor(kernel->y(), rhs); + checkTensor(kernel->output(), op); + EXPECT_THAT(kernel->params().adj_x, Eq(op->adj_x())); + EXPECT_THAT(kernel->params().adj_y, Eq(op->adj_y())); +} + +TEST_F(KernelBuilderTest, Cast) +{ + auto *input = createInputNode(); + + auto *op = createNode<luci::CircleCast>(); + op->x(input); + + auto kernel = buildKernel<kernels::Cast>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input(), input); + checkTensor(kernel->output(), op); +} + TEST_F(KernelBuilderTest, Concatenation) { auto *input1 = createInputNode(); @@ -192,6 +263,7 @@ TEST_F(KernelBuilderTest, Concatenation) checkTensor(kernel->input(1), input2); checkTensor(kernel->output(), op); EXPECT_THAT(kernel->params().axis, Eq(op->axis())); + EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction())); } TEST_F(KernelBuilderTest, Conv2D) @@ -279,6 +351,26 @@ TEST_F(KernelBuilderTest, DepthwiseConv2D) EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction())); } +TEST_F(KernelBuilderTest, Div) +{ + auto *input1 = createInputNode(); + auto *input2 = createInputNode(); + + auto *op = createNode<luci::CircleDiv>(); + op->x(input1); + op->y(input2); + + op->fusedActivationFunction(luci::FusedActFunc::RELU); + + auto kernel = buildKernel<kernels::Div>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input1(), input1); + checkTensor(kernel->input2(), input2); + checkTensor(kernel->output(), op); + EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction())); +} + TEST_F(KernelBuilderTest, Elu) { auto *input = createInputNode(); @@ -293,6 +385,68 @@ TEST_F(KernelBuilderTest, Elu) checkTensor(kernel->output(), op); } +TEST_F(KernelBuilderTest, Exp) +{ + auto *input = createInputNode(); + + auto *op = createNode<luci::CircleExp>(); + op->x(input); + + auto kernel = buildKernel<kernels::Exp>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input(), input); + checkTensor(kernel->output(), op); +} + +TEST_F(KernelBuilderTest, Floor) +{ + auto *input = createInputNode(); + + auto *op = createNode<luci::CircleFloor>(); + op->x(input); + + auto kernel = buildKernel<kernels::Floor>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input(), input); + checkTensor(kernel->output(), op); +} + +TEST_F(KernelBuilderTest, FloorDiv) +{ + auto *x = createInputNode(); + auto *y = createInputNode(); + + auto *op = createNode<luci::CircleFloorDiv>(); + op->x(x); + op->y(y); + + auto kernel = buildKernel<kernels::FloorDiv>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->x(), x); + checkTensor(kernel->y(), y); + checkTensor(kernel->output(), op); +} + +TEST_F(KernelBuilderTest, Equal) +{ + auto *x_input = createInputNode(); + auto *y_input = createInputNode(); + + auto *op = createNode<luci::CircleEqual>(); + op->x(x_input); + op->y(y_input); + + auto kernel = buildKernel<kernels::Equal>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->x(), x_input); + checkTensor(kernel->y(), y_input); + checkTensor(kernel->output(), op); +} + TEST_F(KernelBuilderTest, FullyConnected) { auto *input = createInputNode(); @@ -316,6 +470,65 @@ TEST_F(KernelBuilderTest, FullyConnected) EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction())); } +TEST_F(KernelBuilderTest, Greater) +{ + auto *x_input = createInputNode(); + auto *y_input = createInputNode(); + + auto *op = createNode<luci::CircleGreater>(); + op->x(x_input); + op->y(y_input); + + auto kernel = buildKernel<kernels::Greater>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->x(), x_input); + checkTensor(kernel->y(), y_input); + checkTensor(kernel->output(), op); +} + +TEST_F(KernelBuilderTest, GreaterEqual) +{ + auto *x_input = createInputNode(); + auto *y_input = createInputNode(); + + auto *op = createNode<luci::CircleGreaterEqual>(); + op->x(x_input); + op->y(y_input); + + auto kernel = buildKernel<kernels::GreaterEqual>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->x(), x_input); + checkTensor(kernel->y(), y_input); + checkTensor(kernel->output(), op); +} + +TEST_F(KernelBuilderTest, InstanceNorm) +{ + auto *input = createInputNode(); + auto *gamma = createInputNode(); + auto *beta = createInputNode(); + + auto *op = createNode<luci::CircleInstanceNorm>(); + op->input(input); + op->gamma(gamma); + op->beta(beta); + + op->epsilon(1e-05); + op->fusedActivationFunction(luci::FusedActFunc::RELU); + + auto kernel = buildKernel<kernels::InstanceNorm>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input(), input); + checkTensor(kernel->gamma(), gamma); + checkTensor(kernel->beta(), beta); + checkTensor(kernel->output(), op); + EXPECT_THAT(kernel->params().epsilon, Eq(op->epsilon())); + EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction())); +} + TEST_F(KernelBuilderTest, L2Normalize) { auto *input = createInputNode(); @@ -377,6 +590,40 @@ TEST_F(KernelBuilderTest, LeakyRelu) EXPECT_THAT(kernel->params().alpha, Eq(op->alpha())); } +TEST_F(KernelBuilderTest, Less) +{ + auto *x_input = createInputNode(); + auto *y_input = createInputNode(); + + auto *op = createNode<luci::CircleLess>(); + op->x(x_input); + op->y(y_input); + + auto kernel = buildKernel<kernels::Less>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->x(), x_input); + checkTensor(kernel->y(), y_input); + checkTensor(kernel->output(), op); +} + +TEST_F(KernelBuilderTest, LessEqual) +{ + auto *x_input = createInputNode(); + auto *y_input = createInputNode(); + + auto *op = createNode<luci::CircleLessEqual>(); + op->x(x_input); + op->y(y_input); + + auto kernel = buildKernel<kernels::LessEqual>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->x(), x_input); + checkTensor(kernel->y(), y_input); + checkTensor(kernel->output(), op); +} + TEST_F(KernelBuilderTest, LocalResponseNormalization) { auto *input = createInputNode(); @@ -400,6 +647,54 @@ TEST_F(KernelBuilderTest, LocalResponseNormalization) EXPECT_THAT(kernel->params().beta, Eq(op->beta())); } +TEST_F(KernelBuilderTest, LogicalAnd) +{ + auto *input1 = createInputNode(); + auto *input2 = createInputNode(); + + auto *op = createNode<luci::CircleLogicalAnd>(); + op->x(input1); + op->y(input2); + + auto kernel = buildKernel<kernels::LogicalAnd>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input1(), input1); + checkTensor(kernel->input2(), input2); + checkTensor(kernel->output(), op); +} + +TEST_F(KernelBuilderTest, LogicalNot) +{ + auto *input = createInputNode(); + + auto *op = createNode<luci::CircleLogicalNot>(); + op->x(input); + + auto kernel = buildKernel<kernels::LogicalNot>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input(), input); + checkTensor(kernel->output(), op); +} + +TEST_F(KernelBuilderTest, LogicalOr) +{ + auto *input1 = createInputNode(); + auto *input2 = createInputNode(); + + auto *op = createNode<luci::CircleLogicalOr>(); + op->x(input1); + op->y(input2); + + auto kernel = buildKernel<kernels::LogicalOr>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input1(), input1); + checkTensor(kernel->input2(), input2); + checkTensor(kernel->output(), op); +} + TEST_F(KernelBuilderTest, Logistic) { auto *input = createInputNode(); @@ -414,6 +709,37 @@ TEST_F(KernelBuilderTest, Logistic) checkTensor(kernel->output(), op); } +TEST_F(KernelBuilderTest, LogSoftmax) +{ + auto *input = createInputNode(); + + auto *op = createNode<luci::CircleLogSoftmax>(); + op->logits(input); + + auto kernel = buildKernel<kernels::LogSoftmax>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input(), input); + checkTensor(kernel->output(), op); +} + +TEST_F(KernelBuilderTest, Maximum) +{ + auto *input1 = createInputNode(); + auto *input2 = createInputNode(); + + auto *op = createNode<luci::CircleMaximum>(); + op->x(input1); + op->y(input2); + + auto kernel = buildKernel<kernels::Maximum>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input1(), input1); + checkTensor(kernel->input2(), input2); + checkTensor(kernel->output(), op); +} + TEST_F(KernelBuilderTest, MaxPool2D) { auto *input = createInputNode(); @@ -461,6 +787,23 @@ TEST_F(KernelBuilderTest, Mean) EXPECT_THAT(kernel->params().keep_dims, Eq(op->keep_dims())); } +TEST_F(KernelBuilderTest, Minimum) +{ + auto *input1 = createInputNode(); + auto *input2 = createInputNode(); + + auto *op = createNode<luci::CircleMinimum>(); + op->x(input1); + op->y(input2); + + auto kernel = buildKernel<kernels::Minimum>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input1(), input1); + checkTensor(kernel->input2(), input2); + checkTensor(kernel->output(), op); +} + TEST_F(KernelBuilderTest, Mul) { auto *input1 = createInputNode(); @@ -481,6 +824,62 @@ TEST_F(KernelBuilderTest, Mul) EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction())); } +TEST_F(KernelBuilderTest, Neg) +{ + auto *input = createInputNode(); + + auto *op = createNode<luci::CircleNeg>(); + op->x(input); + + auto kernel = buildKernel<kernels::Neg>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input(), input); + checkTensor(kernel->output(), op); +} + +TEST_F(KernelBuilderTest, NotEqual) +{ + auto *x_input = createInputNode(); + auto *y_input = createInputNode(); + + auto *op = createNode<luci::CircleNotEqual>(); + op->x(x_input); + op->y(y_input); + + auto kernel = buildKernel<kernels::NotEqual>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->x(), x_input); + checkTensor(kernel->y(), y_input); + checkTensor(kernel->output(), op); +} + +TEST_F(KernelBuilderTest, OneHot) +{ + auto *indices = createInputNode(); + auto *depth = createInputNode(); + auto *on_value = createInputNode(); + auto *off_value = createInputNode(); + auto axis = 1; + + auto *op = createNode<luci::CircleOneHot>(); + op->indices(indices); + op->depth(depth); + op->on_value(on_value); + op->off_value(off_value); + op->axis(axis); + + auto kernel = buildKernel<kernels::OneHot>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->indices(), indices); + checkTensor(kernel->depth(), depth); + checkTensor(kernel->on_value(), on_value); + checkTensor(kernel->off_value(), off_value); + EXPECT_THAT(kernel->params().axis, Eq(op->axis())); +} + TEST_F(KernelBuilderTest, Pad) { auto *input = createInputNode(); @@ -498,6 +897,88 @@ TEST_F(KernelBuilderTest, Pad) checkTensor(kernel->output(), op); } +TEST_F(KernelBuilderTest, PadV2) +{ + auto *input = createInputNode(); + auto *paddings = createInputNode(); + auto *constant_values = createInputNode(); + + auto *op = createNode<luci::CirclePadV2>(); + op->input(input); + op->paddings(paddings); + op->constant_values(constant_values); + + auto kernel = buildKernel<kernels::PadV2>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input(), input); + checkTensor(kernel->paddings(), paddings); + checkTensor(kernel->constant_values(), constant_values); + checkTensor(kernel->output(), op); +} + +TEST_F(KernelBuilderTest, Pow) +{ + auto *input1 = createInputNode(); + auto *input2 = createInputNode(); + + auto *op = createNode<luci::CirclePow>(); + op->x(input1); + op->y(input2); + + auto kernel = buildKernel<kernels::Pow>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input1(), input1); + checkTensor(kernel->input2(), input2); + checkTensor(kernel->output(), op); +} + +TEST_F(KernelBuilderTest, PRelu) +{ + auto *input = createInputNode(); + auto *alpha = createInputNode(); + + auto *op = createNode<luci::CirclePRelu>(); + op->input(input); + op->alpha(alpha); + + auto kernel = buildKernel<kernels::PRelu>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input(), input); + checkTensor(kernel->alpha(), alpha); + checkTensor(kernel->output(), op); +} + +TEST_F(KernelBuilderTest, Relu) +{ + auto *input = createInputNode(); + + auto *op = createNode<luci::CircleRelu>(); + op->features(input); + + auto kernel = buildKernel<kernels::Relu>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input(), input); + checkTensor(kernel->output(), op); +} + +TEST_F(KernelBuilderTest, Relu6) +{ + auto *input = createInputNode(); + + auto *op = createNode<luci::CircleRelu6>(); + op->features(input); + + auto kernel = buildKernel<kernels::Relu6>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input(), input); + checkTensor(kernel->output(), op); +} + TEST_F(KernelBuilderTest, Reshape) { auto *input = createInputNode(); @@ -515,6 +996,48 @@ TEST_F(KernelBuilderTest, Reshape) checkTensor(kernel->output(), op); } +TEST_F(KernelBuilderTest, ResizeBilinear) +{ + auto *input = createInputNode(); + auto *size = createInputNode(); + + auto *op = createNode<luci::CircleResizeBilinear>(); + op->input(input); + op->size(size); + op->align_corners(true); + op->half_pixel_centers(true); + + auto kernel = buildKernel<kernels::ResizeBilinear>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input(), input); + checkTensor(kernel->size(), size); + checkTensor(kernel->output(), op); + EXPECT_THAT(kernel->params().align_corners, Eq(op->align_corners())); + EXPECT_THAT(kernel->params().half_pixel_centers, Eq(op->half_pixel_centers())); +} + +TEST_F(KernelBuilderTest, ResizeNearestNeighbor) +{ + auto *input = createInputNode(); + auto *size = createInputNode(); + + auto *op = createNode<luci::CircleResizeNearestNeighbor>(); + op->input(input); + op->size(size); + op->align_corners(true); + + auto kernel = buildKernel<kernels::ResizeNearestNeighbor>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input(), input); + checkTensor(kernel->size(), size); + checkTensor(kernel->output(), op); + EXPECT_THAT(kernel->params().align_corners, Eq(op->align_corners())); + // TODO currently half_pixel_centers are not implemented on CircleResizeNearestNeighbor + // after adding, need to be updated. +} + TEST_F(KernelBuilderTest, ReverseV2) { auto *input = createInputNode(); @@ -524,7 +1047,7 @@ TEST_F(KernelBuilderTest, ReverseV2) op->tensor(input); op->axis(axes); - auto kernel = buildKernel<kernels::Reverse>(op); + auto kernel = buildKernel<kernels::ReverseV2>(op); ASSERT_THAT(kernel, NotNull()); checkTensor(kernel->input(), input); @@ -622,6 +1145,31 @@ TEST_F(KernelBuilderTest, Split) checkTensor(kernel->output(1), output2); } +TEST_F(KernelBuilderTest, SplitV) +{ + auto *input = createInputNode(); + auto *size_splits = createInputNode(); + auto *axis = createInputNode(); + auto *op = createNode<luci::CircleSplitV>(); + auto *output0 = createNodeOut<luci::CircleSplitVOut>(op, 0); + auto *output1 = createNodeOut<luci::CircleSplitVOut>(op, 1); + + op->input(input); + op->size_splits(size_splits); + op->split_dim(axis); + + op->num_split(2); + + auto kernel = buildKernel<kernels::SplitV>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input(), input); + checkTensor(kernel->size_splits(), size_splits); + checkTensor(kernel->axis(), axis); + checkTensor(kernel->output(0), output0); + checkTensor(kernel->output(1), output1); +} + TEST_F(KernelBuilderTest, Sqrt) { auto *input = createInputNode(); @@ -636,6 +1184,23 @@ TEST_F(KernelBuilderTest, Sqrt) checkTensor(kernel->output(), op); } +TEST_F(KernelBuilderTest, SquaredDifference) +{ + auto *input1 = createInputNode(); + auto *input2 = createInputNode(); + + auto *op = createNode<luci::CircleSquaredDifference>(); + op->x(input1); + op->y(input2); + + auto kernel = buildKernel<kernels::SquaredDifference>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input1(), input1); + checkTensor(kernel->input2(), input2); + checkTensor(kernel->output(), op); +} + TEST_F(KernelBuilderTest, Squeeze) { auto *input = createInputNode(); @@ -687,6 +1252,26 @@ TEST_F(KernelBuilderTest, StridedSlice) EXPECT_THAT(kernel->params().shrink_axis_mask, Eq(op->shrink_axis_mask())); } +TEST_F(KernelBuilderTest, Sub) +{ + auto *input1 = createInputNode(); + auto *input2 = createInputNode(); + + auto *op = createNode<luci::CircleSub>(); + op->x(input1); + op->y(input2); + + op->fusedActivationFunction(luci::FusedActFunc::RELU); + + auto kernel = buildKernel<kernels::Sub>(op); + ASSERT_THAT(kernel, NotNull()); + + checkTensor(kernel->input1(), input1); + checkTensor(kernel->input2(), input2); + checkTensor(kernel->output(), op); + EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction())); +} + TEST_F(KernelBuilderTest, Tanh) { auto *input = createInputNode(); @@ -734,6 +1319,7 @@ TEST_F(KernelBuilderTest, TransposeConv) op->padding(luci::Padding::SAME); op->stride()->h(11); op->stride()->w(13); + op->fusedActivationFunction(luci::FusedActFunc::NONE); auto kernel = buildKernel<kernels::TransposeConv>(op); ASSERT_THAT(kernel, NotNull()); @@ -746,6 +1332,7 @@ TEST_F(KernelBuilderTest, TransposeConv) EXPECT_THAT(kernel->params().padding, Eq(op->padding())); EXPECT_THAT(kernel->params().stride_height, Eq(op->stride()->h())); EXPECT_THAT(kernel->params().stride_width, Eq(op->stride()->w())); + EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction())); } TEST_F(KernelBuilderTest, Unpack) diff --git a/compiler/luci-interpreter/src/loader/KernelBuilderHelper.cpp b/compiler/luci-interpreter/src/loader/KernelBuilderHelper.cpp new file mode 100644 index 000000000..23c96a6db --- /dev/null +++ b/compiler/luci-interpreter/src/loader/KernelBuilderHelper.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2021 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 "loader/KernelBuilderHelper.h" + +#include <luci/IR/Nodes/CircleOutput.h> + +namespace luci_interpreter +{ + +const Tensor *KernelBuilderHelper::getInputTensor(const loco::Node *node) const +{ + const Tensor *tensor = _node_to_tensor.at(node); + assert(tensor != nullptr); + return tensor; +} + +const Tensor *KernelBuilderHelper::getOptionalInputTensor(const loco::Node *node) const +{ + if (dynamic_cast<const luci::CircleOutputExclude *>(node)) + { + return nullptr; + } + return getInputTensor(node); +} + +Tensor *KernelBuilderHelper::getOutputTensor(const loco::Node *node) const +{ + Tensor *tensor = _node_to_tensor.at(node); + assert(tensor != nullptr); + return tensor; +} + +std::vector<Tensor *> +KernelBuilderHelper::getOutputTensors(const std::vector<const loco::Node *> &nodes) const +{ + std::vector<Tensor *> tensors; + tensors.reserve(nodes.size()); + for (const loco::Node *node : nodes) + tensors.push_back(getOutputTensor(node)); + return tensors; +} + +RuntimeGraph *KernelBuilderHelper::getRuntimeGraph(const loco::Graph *graph) const +{ + RuntimeGraph *runtime_graph = _graph_to_runtime_graph.at(graph); + assert(runtime_graph != nullptr); + return runtime_graph; +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/KernelBuilderHelper.h b/compiler/luci-interpreter/src/loader/KernelBuilderHelper.h new file mode 100644 index 000000000..d6fb253b1 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/KernelBuilderHelper.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2021 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 LUCI_INTERPRETER_LOADER_KERNELBUILDER_HELPER_H +#define LUCI_INTERPRETER_LOADER_KERNELBUILDER_HELPER_H + +#include "core/Kernel.h" +#include "core/RuntimeGraph.h" + +#include <loco/IR/Graph.h> +#include <loco/IR/Node.h> + +#include <vector> +#include <unordered_map> + +namespace luci_interpreter +{ + +class KernelBuilderHelper +{ +public: + KernelBuilderHelper( + const std::unordered_map<const loco::Graph *, RuntimeGraph *> &graph_to_runtime_graph, + const std::unordered_map<const loco::Node *, Tensor *> &node_to_tensor) + : _graph_to_runtime_graph(graph_to_runtime_graph), _node_to_tensor(node_to_tensor) + { + } + +public: + const Tensor *getInputTensor(const loco::Node *node) const; + const Tensor *getOptionalInputTensor(const loco::Node *node) const; + + Tensor *getOutputTensor(const loco::Node *node) const; + std::vector<Tensor *> getOutputTensors(const std::vector<const loco::Node *> &nodes) const; + + RuntimeGraph *getRuntimeGraph(const loco::Graph *graph) const; + +public: + const std::unordered_map<const loco::Graph *, RuntimeGraph *> &graph_to_runtime_graph() const + { + return _graph_to_runtime_graph; + } + + const std::unordered_map<const loco::Node *, Tensor *> &node_to_tensor() const + { + return _node_to_tensor; + } + +private: + const std::unordered_map<const loco::Graph *, RuntimeGraph *> &_graph_to_runtime_graph; + const std::unordered_map<const loco::Node *, Tensor *> &_node_to_tensor; +}; + +template <typename CircleNodeOut> +std::vector<const loco::Node *> collectOutputNodes(const loco::Node *node) +{ + std::vector<const CircleNodeOut *> output_nodes; + for (const loco::Node *loco_node : loco::succs(node)) + { + output_nodes.push_back(loco::must_cast<const CircleNodeOut *>(loco_node)); + } + std::sort(output_nodes.begin(), output_nodes.end(), + [](const CircleNodeOut *node1, const CircleNodeOut *node2) { + return node1->index() < node2->index(); + }); + return {output_nodes.cbegin(), output_nodes.cend()}; +} + +} // namespace luci_interpreter + +#endif // LUCI_INTERPRETER_LOADER_KERNELBUILDER_HELPER_H diff --git a/compiler/luci-interpreter/src/loader/ModuleLoader.cpp b/compiler/luci-interpreter/src/loader/ModuleLoader.cpp index b9a2ae0a9..2f278b087 100644 --- a/compiler/luci-interpreter/src/loader/ModuleLoader.cpp +++ b/compiler/luci-interpreter/src/loader/ModuleLoader.cpp @@ -23,9 +23,10 @@ namespace luci_interpreter ModuleLoader::ModuleLoader(const luci::Module *module, RuntimeModule *runtime_module, RuntimeToIR &runtime_to_ir, - std::unordered_map<const loco::Node *, Tensor *> &node_to_tensor) - : _module(module), _runtime_module(runtime_module), _runtime_to_ir(runtime_to_ir), - _node_to_tensor(node_to_tensor) + std::unordered_map<const loco::Node *, Tensor *> &node_to_tensor, + IMemoryManager *memory_manager) + : _module(module), _runtime_module(runtime_module), _runtime_to_ir(runtime_to_ir), + _node_to_tensor(node_to_tensor), _memory_manager(memory_manager) { } @@ -35,14 +36,14 @@ void ModuleLoader::load() // process for control flow nodes. for (size_t i = 0; i < _module->size(); ++i) { - _graph_to_runtime_graph.emplace(_module->graph(i), _runtime_module->addGraph()); + _graph_to_runtime_graph.emplace(_module->graph(i), _runtime_module->addGraph(_memory_manager)); } for (size_t i = 0; i < _module->size(); ++i) { const loco::Graph *graph = _module->graph(i); RuntimeGraph *runtime_graph = _graph_to_runtime_graph.at(graph); GraphLoader loader(graph, runtime_graph, _runtime_to_ir, _graph_to_runtime_graph, - _node_to_tensor); + _node_to_tensor, _memory_manager); loader.loadTensors(); loader.initInputOutputTensors(); loader.loadOperators(); diff --git a/compiler/luci-interpreter/src/loader/ModuleLoader.h b/compiler/luci-interpreter/src/loader/ModuleLoader.h index 1af0ed747..11326a2ee 100644 --- a/compiler/luci-interpreter/src/loader/ModuleLoader.h +++ b/compiler/luci-interpreter/src/loader/ModuleLoader.h @@ -19,6 +19,7 @@ #include "core/RuntimeModule.h" #include "loader/RuntimeToIR.h" +#include "luci_interpreter/MemoryManager.h" #include <luci/IR/Module.h> @@ -32,11 +33,13 @@ class ModuleLoader public: ModuleLoader(const luci::Module *module, RuntimeModule *runtime_module, RuntimeToIR &runtime_to_ir, - std::unordered_map<const loco::Node *, Tensor *> &node_to_tensor); + std::unordered_map<const loco::Node *, Tensor *> &node_to_tensor, + IMemoryManager *memory_manager); void load(); private: + IMemoryManager *_memory_manager; const luci::Module *_module; RuntimeModule *_runtime_module; RuntimeToIR &_runtime_to_ir; diff --git a/compiler/luci-interpreter/src/loader/nodes/Abs.cpp b/compiler/luci-interpreter/src/loader/nodes/Abs.cpp new file mode 100644 index 000000000..394711145 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Abs.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2022 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 "Builders.h" + +#include "kernels/Abs.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleAbs(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleAbs *>(circle_node); + assert(node->arity() == 1); + + const Tensor *input = helper.getInputTensor(node->x()); + Tensor *output = helper.getOutputTensor(node); + + return std::make_unique<kernels::Abs>(input, output); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/Add.cpp b/compiler/luci-interpreter/src/loader/nodes/Add.cpp new file mode 100644 index 000000000..501e84752 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Add.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/Add.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleAdd(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleAdd *>(circle_node); + assert(node->arity() == 2); + + const Tensor *input1 = helper.getInputTensor(node->x()); + const Tensor *input2 = helper.getInputTensor(node->y()); + Tensor *output = helper.getOutputTensor(node); + + AddParams params{}; + params.activation = node->fusedActivationFunction(); + + return std::make_unique<kernels::Add>(input1, input2, output, params); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/ArgMax.cpp b/compiler/luci-interpreter/src/loader/nodes/ArgMax.cpp new file mode 100644 index 000000000..f3ca55744 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/ArgMax.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/ArgMax.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleArgMax(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleArgMax *>(circle_node); + assert(node->arity() == 2); + const Tensor *input = helper.getInputTensor(node->input()); + const Tensor *axis = helper.getInputTensor(node->dimension()); + Tensor *output = helper.getOutputTensor(node); + + ArgMaxParams params{}; + params.output_type = node->output_type(); + + return std::make_unique<kernels::ArgMax>(input, axis, output, params); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/AveragePool2D.cpp b/compiler/luci-interpreter/src/loader/nodes/AveragePool2D.cpp new file mode 100644 index 000000000..a8135706f --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/AveragePool2D.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/AveragePool2D.h" +#include <luci/Plan/CircleNodeExecutionPlan.h> + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleAveragePool2D(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleAveragePool2D *>(circle_node); + assert(node->arity() == 1); + + const Tensor *input = helper.getInputTensor(node->value()); + Tensor *output = helper.getOutputTensor(node); + + Pool2DParams params{}; + params.padding = node->padding(); + params.filter_height = node->filter()->h(); + params.filter_width = node->filter()->w(); + params.stride_height = node->stride()->h(); + params.stride_width = node->stride()->w(); + params.activation = node->fusedActivationFunction(); + + // It is unknown what data will be stored in scratchpad tensor, + // using UINT8 as a most general option + auto scratchpad = std::make_unique<Tensor>(DataType::U8, Shape({}), AffineQuantization{}, ""); + scratchpad->set_observable(false); + scratchpad->set_data_buffer(nullptr); + // If node has execution plan then read memory offsets for scratchpad temporary tensor + // from the beginning of shared memory buffer. + // Used in Static Memory Manager. + // TODO move tensors offset initialization to one place + if (luci::has_execution_plan(node)) + { + const auto execution_plan = luci::get_execution_plan(node); + // Check whether the offset for the current CircleConv2D temporary was found. + if (execution_plan.offsets().size() > 1) + // If this is true, then we keep this offset in scratchpad. + scratchpad->set_offset(execution_plan.offsets().at(1)); + } + Tensor *tmp = helper.getRuntimeGraph(node->graph())->addTensor(std::move(scratchpad)); + + return std::make_unique<kernels::AveragePool2D>(input, output, tmp, params); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/BatchMatMul.cpp b/compiler/luci-interpreter/src/loader/nodes/BatchMatMul.cpp new file mode 100644 index 000000000..9da2f6d93 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/BatchMatMul.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2022 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 "Builders.h" + +#include "kernels/BatchMatMul.h" +#include <luci/Plan/CircleNodeExecutionPlan.h> + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleBatchMatMul(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleBatchMatMul *>(circle_node); + assert(node->arity() == 2); + + const Tensor *lhs = helper.getInputTensor(node->x()); + const Tensor *rhs = helper.getInputTensor(node->y()); + Tensor *output = helper.getOutputTensor(node); + + auto lhs_scratchpad = + std::make_unique<Tensor>(lhs->element_type(), Shape({}), AffineQuantization{}, ""); + lhs_scratchpad->set_observable(false); + lhs_scratchpad->set_data_buffer(nullptr); + auto rhs_scratchpad = + std::make_unique<Tensor>(rhs->element_type(), Shape({}), AffineQuantization{}, ""); + rhs_scratchpad->set_observable(false); + rhs_scratchpad->set_data_buffer(nullptr); + // If node has execution plan then read memory offsets for scratchpad temporary tensor + // from the beginning of shared memory buffer. + // Used in Static Memory Manager. + // TODO move tensors offset initialization to one place + if (luci::has_execution_plan(node)) + { + const auto execution_plan = luci::get_execution_plan(node); + // Check whether the offset for the current BatchMatMul temporary was found. + if (execution_plan.offsets().size() > 1) + { + assert(execution_plan.offsets().size() == 3); + + // If this is true, then we keep this offset in scratchpad. + lhs_scratchpad->set_offset(execution_plan.offsets().at(1)); + rhs_scratchpad->set_offset(execution_plan.offsets().at(2)); + } + } + Tensor *lhs_tmp = helper.getRuntimeGraph(node->graph())->addTensor(std::move(lhs_scratchpad)); + Tensor *rhs_tmp = helper.getRuntimeGraph(node->graph())->addTensor(std::move(rhs_scratchpad)); + + BatchMatMulParams params; + params.adj_x = node->adj_x(); + params.adj_y = node->adj_y(); + + return std::make_unique<kernels::BatchMatMul>(lhs, rhs, output, lhs_tmp, rhs_tmp, params); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/BatchToSpaceND.cpp b/compiler/luci-interpreter/src/loader/nodes/BatchToSpaceND.cpp new file mode 100644 index 000000000..ac6ebb30f --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/BatchToSpaceND.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/BatchToSpaceND.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleBatchToSpaceND(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleBatchToSpaceND *>(circle_node); + assert(node->arity() == 3); + + const Tensor *input = helper.getInputTensor(node->input()); + const Tensor *block_shape = helper.getInputTensor(node->block_shape()); + const Tensor *crops = helper.getInputTensor(node->crops()); + Tensor *output = helper.getOutputTensor(node); + + return std::make_unique<kernels::BatchToSpaceND>(input, block_shape, crops, output); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/Builders.h b/compiler/luci-interpreter/src/loader/nodes/Builders.h new file mode 100644 index 000000000..eab284008 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Builders.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2021 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 LUCI_INTERPRETER_LOADER_NODES_BUILDERS_H +#define LUCI_INTERPRETER_LOADER_NODES_BUILDERS_H + +#include "loader/KernelBuilderHelper.h" + +#include "luci/IR/CircleNodes.h" + +namespace luci_interpreter +{ + +#define REGISTER_KERNEL(name) \ + std::unique_ptr<Kernel> build_kernel_Circle##name(const luci::CircleNode *circle_node, \ + KernelBuilderHelper &helper); + +#include "KernelsToBuild.lst" + +#undef REGISTER_KERNEL + +} // namespace luci_interpreter + +#endif // LUCI_INTERPRETER_LOADER_NODES_BUILDERS_H diff --git a/compiler/luci-interpreter/src/loader/nodes/Cast.cpp b/compiler/luci-interpreter/src/loader/nodes/Cast.cpp new file mode 100644 index 000000000..a16354c96 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Cast.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/Cast.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleCast(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleCast *>(circle_node); + + assert(node->arity() == 1); + + const Tensor *input = helper.getInputTensor(node->x()); + Tensor *output = helper.getOutputTensor(node); + + return std::make_unique<kernels::Cast>(input, output); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/Concatenation.cpp b/compiler/luci-interpreter/src/loader/nodes/Concatenation.cpp new file mode 100644 index 000000000..ba2564ea2 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Concatenation.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/Concatenation.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleConcatenation(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleConcatenation *>(circle_node); + std::vector<const Tensor *> inputs(node->numValues()); + for (uint32_t i = 0; i < node->numValues(); ++i) + { + inputs[i] = helper.getInputTensor(node->values(i)); + } + Tensor *output = helper.getOutputTensor(node); + + ConcatenationParams params{}; + params.axis = node->axis(); + params.activation = node->fusedActivationFunction(); + + return std::make_unique<kernels::Concatenation>(std::move(inputs), output, params); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/Conv2D.cpp b/compiler/luci-interpreter/src/loader/nodes/Conv2D.cpp new file mode 100644 index 000000000..218165e20 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Conv2D.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/Conv2D.h" +#include <luci/Plan/CircleNodeExecutionPlan.h> + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleConv2D(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleConv2D *>(circle_node); + assert(node->arity() == 3); + + const Tensor *input = helper.getInputTensor(node->input()); + const Tensor *filter = helper.getInputTensor(node->filter()); + const Tensor *bias = helper.getOptionalInputTensor(node->bias()); + Tensor *output = helper.getOutputTensor(node); + + // It is unknown what data will be stored in scratchpad tensor, + // using UINT8 as a most general option + auto scratchpad = std::make_unique<Tensor>(DataType::U8, Shape({}), AffineQuantization{}, ""); + scratchpad->set_observable(false); + scratchpad->set_data_buffer(nullptr); + // If node has execution plan then read memory offsets for scratchpad temporary tensor + // from the beginning of shared memory buffer. + // Used in Static Memory Manager. + // TODO move tensors offset initialization to one place + if (luci::has_execution_plan(node)) + { + const auto execution_plan = luci::get_execution_plan(node); + // Check whether the offset for the current CircleConv2D temporary was found. + if (execution_plan.offsets().size() > 1) + // If this is true, then we keep this offset in scratchpad. + scratchpad->set_offset(execution_plan.offsets().at(1)); + } + Tensor *tmp = helper.getRuntimeGraph(node->graph())->addTensor(std::move(scratchpad)); + + Conv2DParams params{}; + params.padding = node->padding(); + params.stride_height = node->stride()->h(); + params.stride_width = node->stride()->w(); + params.dilation_height_factor = node->dilation()->h(); + params.dilation_width_factor = node->dilation()->w(); + params.activation = node->fusedActivationFunction(); + + return std::make_unique<kernels::Conv2D>(input, filter, bias, output, tmp, params); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/DepthToSpace.cpp b/compiler/luci-interpreter/src/loader/nodes/DepthToSpace.cpp new file mode 100644 index 000000000..174946367 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/DepthToSpace.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/DepthToSpace.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleDepthToSpace(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleDepthToSpace *>(circle_node); + assert(node->arity() == 1); + + const Tensor *input = helper.getInputTensor(node->input()); + Tensor *output = helper.getOutputTensor(node); + + DepthToSpaceParams params{}; + params.block_size = node->block_size(); + + return std::make_unique<kernels::DepthToSpace>(input, output, params); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/DepthwiseConv2D.cpp b/compiler/luci-interpreter/src/loader/nodes/DepthwiseConv2D.cpp new file mode 100644 index 000000000..8af1e3b58 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/DepthwiseConv2D.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/DepthwiseConv2D.h" +#include <luci/Plan/CircleNodeExecutionPlan.h> + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleDepthwiseConv2D(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleDepthwiseConv2D *>(circle_node); + assert(node->arity() == 3); + + const Tensor *input = helper.getInputTensor(node->input()); + const Tensor *filter = helper.getInputTensor(node->filter()); + const Tensor *bias = helper.getInputTensor(node->bias()); + Tensor *output = helper.getOutputTensor(node); + + DepthwiseConv2DParams params{}; + params.padding = node->padding(); + params.depth_multiplier = node->depthMultiplier(); + params.stride_height = node->stride()->h(); + params.stride_width = node->stride()->w(); + params.dilation_height_factor = node->dilation()->h(); + params.dilation_width_factor = node->dilation()->w(); + params.activation = node->fusedActivationFunction(); + + // It is unknown what data will be stored in scratchpad tensor, + // using UINT8 as a most general option + auto scratchpad = std::make_unique<Tensor>(DataType::U8, Shape({}), AffineQuantization{}, ""); + scratchpad->set_observable(false); + scratchpad->set_data_buffer(nullptr); + // If node has execution plan then read memory offsets for scratchpad temporary tensor + // from the beginning of shared memory buffer. + // Used in Static Memory Manager. + // TODO move tensors offset initialization to one place + if (luci::has_execution_plan(node)) + { + const auto execution_plan = luci::get_execution_plan(node); + // Check whether the offset for the current CircleConv2D temporary was found. + if (execution_plan.offsets().size() > 1) + // If this is true, then we keep this offset in scratchpad. + scratchpad->set_offset(execution_plan.offsets().at(1)); + } + Tensor *tmp = helper.getRuntimeGraph(node->graph())->addTensor(std::move(scratchpad)); + + return std::make_unique<kernels::DepthwiseConv2D>(input, filter, bias, output, tmp, params); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/Dequantize.cpp b/compiler/luci-interpreter/src/loader/nodes/Dequantize.cpp new file mode 100644 index 000000000..787322e9b --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Dequantize.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2022 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 "Builders.h" + +#include "kernels/Dequantize.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleDequantize(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleDequantize *>(circle_node); + + const Tensor *input = helper.getInputTensor(node->input()); + Tensor *output = helper.getOutputTensor(node); + + return std::make_unique<kernels::Dequantize>(input, output); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/Div.cpp b/compiler/luci-interpreter/src/loader/nodes/Div.cpp new file mode 100644 index 000000000..0611dfdab --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Div.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/Div.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleDiv(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleDiv *>(circle_node); + assert(node->arity() == 2); + const Tensor *input1 = helper.getInputTensor(node->x()); + const Tensor *input2 = helper.getInputTensor(node->y()); + Tensor *output = helper.getOutputTensor(node); + + DivParams params{}; + params.activation = node->fusedActivationFunction(); + + return std::make_unique<kernels::Div>(input1, input2, output, params); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/Elu.cpp b/compiler/luci-interpreter/src/loader/nodes/Elu.cpp new file mode 100644 index 000000000..a79985e3b --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Elu.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/Elu.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleElu(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleElu *>(circle_node); + assert(node->arity() == 1); + + const Tensor *input = helper.getInputTensor(node->features()); + Tensor *output = helper.getOutputTensor(node); + + return std::make_unique<kernels::Elu>(input, output); +} +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/Equal.cpp b/compiler/luci-interpreter/src/loader/nodes/Equal.cpp new file mode 100644 index 000000000..59692883f --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Equal.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/Equal.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleEqual(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) + +{ + const auto *node = loco::must_cast<const luci::CircleEqual *>(circle_node); + assert(node->arity() == 2); + + const Tensor *x = helper.getInputTensor(node->x()); + const Tensor *y = helper.getInputTensor(node->y()); + Tensor *output = helper.getOutputTensor(node); + + return std::make_unique<kernels::Equal>(x, y, output); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/Exp.cpp b/compiler/luci-interpreter/src/loader/nodes/Exp.cpp new file mode 100644 index 000000000..30d11cb89 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Exp.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/Exp.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleExp(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleExp *>(circle_node); + assert(node->arity() == 1); + + const Tensor *input = helper.getInputTensor(node->x()); + Tensor *output = helper.getOutputTensor(node); + + return std::make_unique<kernels::Exp>(input, output); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/ExpandDims.cpp b/compiler/luci-interpreter/src/loader/nodes/ExpandDims.cpp new file mode 100644 index 000000000..9840c34e5 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/ExpandDims.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2022 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 "Builders.h" + +#include "kernels/ExpandDims.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleExpandDims(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleExpandDims *>(circle_node); + assert(node->arity() == 2); + + const Tensor *input = helper.getInputTensor(node->input()); + const Tensor *axis = helper.getInputTensor(node->axis()); + Tensor *output = helper.getOutputTensor(node); + + return std::make_unique<kernels::ExpandDims>(input, axis, output); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/Fill.cpp b/compiler/luci-interpreter/src/loader/nodes/Fill.cpp new file mode 100644 index 000000000..3aefdf1c5 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Fill.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2022 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 "Builders.h" + +#include "kernels/Fill.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleFill(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleFill *>(circle_node); + assert(node->arity() == 2); + + const auto dims = helper.getInputTensor(node->dims()); + const auto value = helper.getInputTensor(node->value()); + auto output = helper.getOutputTensor(node); + + return std::make_unique<kernels::Fill>(dims, value, output); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/Floor.cpp b/compiler/luci-interpreter/src/loader/nodes/Floor.cpp new file mode 100644 index 000000000..e0a223116 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Floor.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/Floor.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleFloor(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleFloor *>(circle_node); + assert(node->arity() == 1); + + const Tensor *input = helper.getInputTensor(node->x()); + Tensor *output = helper.getOutputTensor(node); + + return std::make_unique<kernels::Floor>(input, output); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/FloorDiv.cpp b/compiler/luci-interpreter/src/loader/nodes/FloorDiv.cpp new file mode 100644 index 000000000..a45d89e38 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/FloorDiv.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/FloorDiv.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleFloorDiv(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleFloorDiv *>(circle_node); + assert(node->arity() == 2); + + const Tensor *x = helper.getInputTensor(node->x()); + const Tensor *y = helper.getInputTensor(node->y()); + Tensor *output = helper.getOutputTensor(node); + + return std::make_unique<kernels::FloorDiv>(x, y, output); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/FloorMod.cpp b/compiler/luci-interpreter/src/loader/nodes/FloorMod.cpp new file mode 100644 index 000000000..a4852f13e --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/FloorMod.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2023 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 "Builders.h" + +#include "kernels/FloorMod.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleFloorMod(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleFloorMod *>(circle_node); + assert(node->arity() == 2); + + const Tensor *x = helper.getInputTensor(node->x()); + const Tensor *y = helper.getInputTensor(node->y()); + Tensor *output = helper.getOutputTensor(node); + + return std::make_unique<kernels::FloorMod>(x, y, output); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/FullyConnected.cpp b/compiler/luci-interpreter/src/loader/nodes/FullyConnected.cpp new file mode 100644 index 000000000..b7b742b8a --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/FullyConnected.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/FullyConnected.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleFullyConnected(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleFullyConnected *>(circle_node); + assert(node->arity() == 3); + + const Tensor *input = helper.getInputTensor(node->input()); + const Tensor *weights = helper.getInputTensor(node->weights()); + const Tensor *bias = helper.getOptionalInputTensor(node->bias()); + Tensor *output = helper.getOutputTensor(node); + + FullyConnectedParams params{}; + params.activation = node->fusedActivationFunction(); + params.keep_num_dims = node->keep_num_dims(); + + return std::make_unique<kernels::FullyConnected>(input, weights, bias, output, params); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/Gather.cpp b/compiler/luci-interpreter/src/loader/nodes/Gather.cpp new file mode 100644 index 000000000..2ee2906e0 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Gather.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2022 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 "Builders.h" + +#include "kernels/Gather.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleGather(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleGather *>(circle_node); + assert(node->arity() == 2); + + const Tensor *params = helper.getInputTensor(node->params()); + const Tensor *indices = helper.getInputTensor(node->indices()); + Tensor *output = helper.getOutputTensor(node); + + GatherParams gparams{}; + gparams.axis = node->axis(); + // TODO support batch_dims + gparams.batch_dims = 0; + + return std::make_unique<kernels::Gather>(params, indices, output, gparams); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/Gelu.cpp b/compiler/luci-interpreter/src/loader/nodes/Gelu.cpp new file mode 100644 index 000000000..fc77a5817 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Gelu.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2023 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 "Builders.h" + +#include "kernels/Gelu.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleGelu(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleGelu *>(circle_node); + assert(node->arity() == 1); + const Tensor *input = helper.getInputTensor(node->features()); + Tensor *output = helper.getOutputTensor(node); + + GeluParams params{}; + params.approximate = node->approximate(); + + return std::make_unique<kernels::Gelu>(input, output, params); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/Greater.cpp b/compiler/luci-interpreter/src/loader/nodes/Greater.cpp new file mode 100644 index 000000000..80aa63cf0 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Greater.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/Greater.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleGreater(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleGreater *>(circle_node); + assert(node->arity() == 2); + + const Tensor *x = helper.getInputTensor(node->x()); + const Tensor *y = helper.getInputTensor(node->y()); + Tensor *output = helper.getOutputTensor(node); + + return std::make_unique<kernels::Greater>(x, y, output); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/GreaterEqual.cpp b/compiler/luci-interpreter/src/loader/nodes/GreaterEqual.cpp new file mode 100644 index 000000000..272f2843b --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/GreaterEqual.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/GreaterEqual.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleGreaterEqual(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleGreaterEqual *>(circle_node); + assert(node->arity() == 2); + + const Tensor *x = helper.getInputTensor(node->x()); + const Tensor *y = helper.getInputTensor(node->y()); + Tensor *output = helper.getOutputTensor(node); + + return std::make_unique<kernels::GreaterEqual>(x, y, output); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/HardSwish.cpp b/compiler/luci-interpreter/src/loader/nodes/HardSwish.cpp new file mode 100644 index 000000000..2e62f2402 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/HardSwish.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023 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 "Builders.h" + +#include "kernels/HardSwish.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleHardSwish(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleHardSwish *>(circle_node); + assert(node->arity() == 1); + + const Tensor *input = helper.getInputTensor(node->features()); + Tensor *output = helper.getOutputTensor(node); + + return std::make_unique<kernels::HardSwish>(input, output); +} +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/If.cpp b/compiler/luci-interpreter/src/loader/nodes/If.cpp new file mode 100644 index 000000000..3ac7d4941 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/If.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/If.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleIf(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleIf *>(circle_node); + auto output_nodes = collectOutputNodes<luci::CircleIfOut>(node); + assert(node->arity() == 1 + node->input_count()); + assert(output_nodes.size() == static_cast<size_t>(node->output_count())); + + const Tensor *cond = helper.getInputTensor(node->cond()); + std::vector<const Tensor *> inputs(node->input_count()); + for (uint32_t i = 0; i < node->input_count(); ++i) + { + inputs[i] = helper.getInputTensor(node->input(i)); + } + std::vector<Tensor *> outputs = helper.getOutputTensors(output_nodes); + + RuntimeGraph *then_graph = helper.getRuntimeGraph(node->then_graph()); + RuntimeGraph *else_graph = helper.getRuntimeGraph(node->else_graph()); + + return std::make_unique<kernels::If>(cond, std::move(inputs), std::move(outputs), then_graph, + else_graph); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/InstanceNorm.cpp b/compiler/luci-interpreter/src/loader/nodes/InstanceNorm.cpp new file mode 100644 index 000000000..06031e5bc --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/InstanceNorm.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/InstanceNorm.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleInstanceNorm(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleInstanceNorm *>(circle_node); + assert(node->arity() == 3); + + const Tensor *input = helper.getInputTensor(node->input()); + const Tensor *gamma = helper.getInputTensor(node->gamma()); + const Tensor *beta = helper.getInputTensor(node->beta()); + + Tensor *output = helper.getOutputTensor(node); + + InstanceNormParams params{}; + params.epsilon = node->epsilon(); + params.activation = node->fusedActivationFunction(); + + return std::make_unique<kernels::InstanceNorm>(input, gamma, beta, output, params); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/L2Normalize.cpp b/compiler/luci-interpreter/src/loader/nodes/L2Normalize.cpp new file mode 100644 index 000000000..6e22e6d4e --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/L2Normalize.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/L2Normalize.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleL2Normalize(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleL2Normalize *>(circle_node); + assert(node->arity() == 1); + + const Tensor *input = helper.getInputTensor(node->x()); + Tensor *output = helper.getOutputTensor(node); + + L2NormParams params{}; + params.activation = node->fusedActivationFunction(); + + return std::make_unique<kernels::L2Normalize>(input, output, params); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/L2Pool2D.cpp b/compiler/luci-interpreter/src/loader/nodes/L2Pool2D.cpp new file mode 100644 index 000000000..95b55896f --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/L2Pool2D.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/L2Pool2D.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleL2Pool2D(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleL2Pool2D *>(circle_node); + assert(node->arity() == 1); + + const Tensor *input = helper.getInputTensor(node->value()); + Tensor *output = helper.getOutputTensor(node); + + Pool2DParams params{}; + params.padding = node->padding(); + params.filter_height = node->filter()->h(); + params.filter_width = node->filter()->w(); + params.stride_height = node->stride()->h(); + params.stride_width = node->stride()->w(); + params.activation = node->fusedActivationFunction(); + + return std::make_unique<kernels::L2Pool2D>(input, output, params); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/LeakyRelu.cpp b/compiler/luci-interpreter/src/loader/nodes/LeakyRelu.cpp new file mode 100644 index 000000000..bbf5067b1 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/LeakyRelu.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/LeakyRelu.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleLeakyRelu(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleLeakyRelu *>(circle_node); + assert(node->arity() == 1); + const Tensor *input = helper.getInputTensor(node->features()); + Tensor *output = helper.getOutputTensor(node); + + LeakyReluParams params{}; + params.alpha = node->alpha(); + + return std::make_unique<kernels::LeakyRelu>(input, output, params); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/Less.cpp b/compiler/luci-interpreter/src/loader/nodes/Less.cpp new file mode 100644 index 000000000..ae914ecc9 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Less.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/Less.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleLess(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleLess *>(circle_node); + assert(node->arity() == 2); + + const Tensor *x = helper.getInputTensor(node->x()); + const Tensor *y = helper.getInputTensor(node->y()); + Tensor *output = helper.getOutputTensor(node); + + return std::make_unique<kernels::Less>(x, y, output); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/LessEqual.cpp b/compiler/luci-interpreter/src/loader/nodes/LessEqual.cpp new file mode 100644 index 000000000..f1b424b55 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/LessEqual.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/LessEqual.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleLessEqual(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleLessEqual *>(circle_node); + assert(node->arity() == 2); + + const Tensor *x = helper.getInputTensor(node->x()); + const Tensor *y = helper.getInputTensor(node->y()); + Tensor *output = helper.getOutputTensor(node); + + return std::make_unique<kernels::LessEqual>(x, y, output); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/LocalResponseNormalization.cpp b/compiler/luci-interpreter/src/loader/nodes/LocalResponseNormalization.cpp new file mode 100644 index 000000000..962ca2d7c --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/LocalResponseNormalization.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/LocalResponseNormalization.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> +build_kernel_CircleLocalResponseNormalization(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleLocalResponseNormalization *>(circle_node); + assert(node->arity() == 1); + const Tensor *input = helper.getInputTensor(node->input()); + Tensor *output = helper.getOutputTensor(node); + + LocalResponseNormalizationParams params{}; + params.radius = node->radius(); + params.bias = node->bias(); + params.alpha = node->alpha(); + params.beta = node->beta(); + + return std::make_unique<kernels::LocalResponseNormalization>(input, output, params); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/Log.cpp b/compiler/luci-interpreter/src/loader/nodes/Log.cpp new file mode 100644 index 000000000..048e3101e --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Log.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023 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 "Builders.h" + +#include "kernels/Log.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleLog(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleLog *>(circle_node); + assert(node->arity() == 1); + + const Tensor *input = helper.getInputTensor(node->x()); + Tensor *output = helper.getOutputTensor(node); + + return std::make_unique<kernels::Log>(input, output); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/LogSoftmax.cpp b/compiler/luci-interpreter/src/loader/nodes/LogSoftmax.cpp new file mode 100644 index 000000000..432204115 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/LogSoftmax.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/LogSoftmax.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleLogSoftmax(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleLogSoftmax *>(circle_node); + assert(node->arity() == 1); + + const Tensor *input = helper.getInputTensor(node->logits()); + Tensor *output = helper.getOutputTensor(node); + + return std::make_unique<kernels::LogSoftmax>(input, output); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/LogicalAnd.cpp b/compiler/luci-interpreter/src/loader/nodes/LogicalAnd.cpp new file mode 100644 index 000000000..bf3cb671a --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/LogicalAnd.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/LogicalAnd.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleLogicalAnd(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleLogicalAnd *>(circle_node); + assert(node->arity() == 2); + + const Tensor *input1 = helper.getInputTensor(node->x()); + const Tensor *input2 = helper.getInputTensor(node->y()); + Tensor *output = helper.getOutputTensor(node); + + return std::make_unique<kernels::LogicalAnd>(input1, input2, output); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/LogicalNot.cpp b/compiler/luci-interpreter/src/loader/nodes/LogicalNot.cpp new file mode 100644 index 000000000..fefcd9a06 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/LogicalNot.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/LogicalNot.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleLogicalNot(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleLogicalNot *>(circle_node); + assert(node->arity() == 1); + + const Tensor *input = helper.getInputTensor(node->x()); + Tensor *output = helper.getOutputTensor(node); + + return std::make_unique<kernels::LogicalNot>(input, output); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/LogicalOr.cpp b/compiler/luci-interpreter/src/loader/nodes/LogicalOr.cpp new file mode 100644 index 000000000..a416cb401 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/LogicalOr.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/LogicalOr.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleLogicalOr(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleLogicalOr *>(circle_node); + assert(node->arity() == 2); + + const Tensor *input1 = helper.getInputTensor(node->x()); + const Tensor *input2 = helper.getInputTensor(node->y()); + Tensor *output = helper.getOutputTensor(node); + + return std::make_unique<kernels::LogicalOr>(input1, input2, output); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/Logistic.cpp b/compiler/luci-interpreter/src/loader/nodes/Logistic.cpp new file mode 100644 index 000000000..4a69deef1 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Logistic.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/Logistic.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleLogistic(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleLogistic *>(circle_node); + assert(node->arity() == 1); + + const Tensor *input = helper.getInputTensor(node->x()); + Tensor *output = helper.getOutputTensor(node); + + return std::make_unique<kernels::Logistic>(input, output); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/MaxPool2D.cpp b/compiler/luci-interpreter/src/loader/nodes/MaxPool2D.cpp new file mode 100644 index 000000000..f66a206ca --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/MaxPool2D.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/MaxPool2D.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleMaxPool2D(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleMaxPool2D *>(circle_node); + assert(node->arity() == 1); + + const Tensor *input = helper.getInputTensor(node->value()); + Tensor *output = helper.getOutputTensor(node); + + Pool2DParams params{}; + params.padding = node->padding(); + params.filter_height = node->filter()->h(); + params.filter_width = node->filter()->w(); + params.stride_height = node->stride()->h(); + params.stride_width = node->stride()->w(); + params.activation = node->fusedActivationFunction(); + + return std::make_unique<kernels::MaxPool2D>(input, output, params); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/Maximum.cpp b/compiler/luci-interpreter/src/loader/nodes/Maximum.cpp new file mode 100644 index 000000000..d0bff776a --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Maximum.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/Maximum.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleMaximum(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleMaximum *>(circle_node); + assert(node->arity() == 2); + + const Tensor *input1 = helper.getInputTensor(node->x()); + const Tensor *input2 = helper.getInputTensor(node->y()); + Tensor *output = helper.getOutputTensor(node); + + return std::make_unique<kernels::Maximum>(input1, input2, output); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/Mean.cpp b/compiler/luci-interpreter/src/loader/nodes/Mean.cpp new file mode 100644 index 000000000..0dec63e79 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Mean.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/Mean.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleMean(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleMean *>(circle_node); + assert(node->arity() == 2); + + const Tensor *input = helper.getInputTensor(node->input()); + const Tensor *axes = helper.getInputTensor(node->reduction_indices()); + Tensor *output = helper.getOutputTensor(node); + + auto temp_index_unique = + std::make_unique<Tensor>(DataType::S32, Shape({}), AffineQuantization{}, ""); + temp_index_unique->set_observable(false); + temp_index_unique->set_data_buffer(nullptr); + Tensor *temp_index = + helper.getRuntimeGraph(node->graph())->addTensor(std::move(temp_index_unique)); + + auto resolved_axes_unique = + std::make_unique<Tensor>(DataType::S32, Shape({}), AffineQuantization{}, ""); + resolved_axes_unique->set_observable(false); + resolved_axes_unique->set_data_buffer(nullptr); + Tensor *resolved_axes = + helper.getRuntimeGraph(node->graph())->addTensor(std::move(resolved_axes_unique)); + + auto temp_sum_unique = + std::make_unique<Tensor>(input->element_type(), Shape({}), AffineQuantization{}, ""); + temp_sum_unique->set_observable(false); + temp_sum_unique->set_data_buffer(nullptr); + Tensor *temp_sum = helper.getRuntimeGraph(node->graph())->addTensor(std::move(temp_sum_unique)); + + ReducerParams params{}; + params.keep_dims = node->keep_dims(); + + return std::make_unique<kernels::Mean>(input, axes, output, temp_index, resolved_axes, temp_sum, + params); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/Minimum.cpp b/compiler/luci-interpreter/src/loader/nodes/Minimum.cpp new file mode 100644 index 000000000..1a49c1090 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Minimum.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/Minimum.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleMinimum(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleMinimum *>(circle_node); + assert(node->arity() == 2); + + const Tensor *input1 = helper.getInputTensor(node->x()); + const Tensor *input2 = helper.getInputTensor(node->y()); + Tensor *output = helper.getOutputTensor(node); + + return std::make_unique<kernels::Minimum>(input1, input2, output); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/MirrorPad.cpp b/compiler/luci-interpreter/src/loader/nodes/MirrorPad.cpp new file mode 100644 index 000000000..b221b4574 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/MirrorPad.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/MirrorPad.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleMirrorPad(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleMirrorPad *>(circle_node); + assert(node->arity() == 2); + + const Tensor *input = helper.getInputTensor(node->input()); + const Tensor *paddings = helper.getInputTensor(node->paddings()); + Tensor *output = helper.getOutputTensor(node); + + MirrorPadParams params{}; + params.mode = node->mode(); + + return std::make_unique<kernels::MirrorPad>(input, paddings, output, params); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/Mul.cpp b/compiler/luci-interpreter/src/loader/nodes/Mul.cpp new file mode 100644 index 000000000..f9984853a --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Mul.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/Mul.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleMul(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleMul *>(circle_node); + assert(node->arity() == 2); + + const Tensor *input1 = helper.getInputTensor(node->x()); + const Tensor *input2 = helper.getInputTensor(node->y()); + Tensor *output = helper.getOutputTensor(node); + + MulParams params{}; + params.activation = node->fusedActivationFunction(); + + return std::make_unique<kernels::Mul>(input1, input2, output, params); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/Neg.cpp b/compiler/luci-interpreter/src/loader/nodes/Neg.cpp new file mode 100644 index 000000000..9a9ecf991 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Neg.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/Neg.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleNeg(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleNeg *>(circle_node); + assert(node->arity() == 1); + + const Tensor *input = helper.getInputTensor(node->x()); + Tensor *output = helper.getOutputTensor(node); + + return std::make_unique<kernels::Neg>(input, output); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/NotEqual.cpp b/compiler/luci-interpreter/src/loader/nodes/NotEqual.cpp new file mode 100644 index 000000000..3916a5854 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/NotEqual.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/NotEqual.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleNotEqual(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleNotEqual *>(circle_node); + assert(node->arity() == 2); + + const Tensor *x = helper.getInputTensor(node->x()); + const Tensor *y = helper.getInputTensor(node->y()); + Tensor *output = helper.getOutputTensor(node); + + return std::make_unique<kernels::NotEqual>(x, y, output); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/OneHot.cpp b/compiler/luci-interpreter/src/loader/nodes/OneHot.cpp new file mode 100644 index 000000000..a40160945 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/OneHot.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/OneHot.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleOneHot(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleOneHot *>(circle_node); + assert(node->arity() == 4); + + const Tensor *indices = helper.getInputTensor(node->indices()); + const Tensor *depth = helper.getInputTensor(node->depth()); + const Tensor *on_value = helper.getInputTensor(node->on_value()); + const Tensor *off_value = helper.getInputTensor(node->off_value()); + Tensor *output = helper.getOutputTensor(node); + + OneHotParams params{}; + params.axis = node->axis(); + + return std::make_unique<kernels::OneHot>(indices, depth, on_value, off_value, output, params); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/PRelu.cpp b/compiler/luci-interpreter/src/loader/nodes/PRelu.cpp new file mode 100644 index 000000000..f3d700c95 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/PRelu.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/PRelu.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CirclePRelu(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CirclePRelu *>(circle_node); + assert(node->arity() == 2); + + const Tensor *input = helper.getInputTensor(node->input()); + const Tensor *alpha = helper.getInputTensor(node->alpha()); + Tensor *output = helper.getOutputTensor(node); + + return std::make_unique<kernels::PRelu>(input, alpha, output); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/Pack.cpp b/compiler/luci-interpreter/src/loader/nodes/Pack.cpp new file mode 100644 index 000000000..efc5850e0 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Pack.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/Pack.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CirclePack(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CirclePack *>(circle_node); + assert(node->arity() == node->values_count()); + + std::vector<const Tensor *> inputs(node->values_count()); + for (uint32_t i = 0; i < node->values_count(); ++i) + { + inputs[i] = helper.getInputTensor(node->values(i)); + } + Tensor *output = helper.getOutputTensor(node); + + PackParams params{}; + params.axis = node->axis(); + params.values_count = node->values_count(); + + return std::make_unique<kernels::Pack>(std::move(inputs), output, params); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/Pad.cpp b/compiler/luci-interpreter/src/loader/nodes/Pad.cpp new file mode 100644 index 000000000..67ce997a7 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Pad.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/Pad.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CirclePad(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CirclePad *>(circle_node); + assert(node->arity() == 2); + + const Tensor *input = helper.getInputTensor(node->input()); + const Tensor *paddings = helper.getInputTensor(node->paddings()); + Tensor *output = helper.getOutputTensor(node); + + return std::make_unique<kernels::Pad>(input, paddings, output); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/PadV2.cpp b/compiler/luci-interpreter/src/loader/nodes/PadV2.cpp new file mode 100644 index 000000000..e378a972a --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/PadV2.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/PadV2.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CirclePadV2(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CirclePadV2 *>(circle_node); + assert(node->arity() == 3); + + const Tensor *input = helper.getInputTensor(node->input()); + const Tensor *paddings = helper.getInputTensor(node->paddings()); + const Tensor *constant_values = helper.getInputTensor(node->constant_values()); + Tensor *output = helper.getOutputTensor(node); + + return std::make_unique<kernels::PadV2>(input, paddings, constant_values, output); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/Pow.cpp b/compiler/luci-interpreter/src/loader/nodes/Pow.cpp new file mode 100644 index 000000000..d32fc3dbb --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Pow.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/Pow.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CirclePow(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CirclePow *>(circle_node); + assert(node->arity() == 2); + + const Tensor *input1 = helper.getInputTensor(node->x()); + const Tensor *input2 = helper.getInputTensor(node->y()); + + Tensor *output = helper.getOutputTensor(node); + + return std::make_unique<kernels::Pow>(input1, input2, output); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/Quantize.cpp b/compiler/luci-interpreter/src/loader/nodes/Quantize.cpp new file mode 100644 index 000000000..cb36fb6da --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Quantize.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2022 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 "Builders.h" + +#include "kernels/Quantize.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleQuantize(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleQuantize *>(circle_node); + assert(node->arity() == 1); + + const Tensor *input = helper.getInputTensor(node->input()); + Tensor *output = helper.getOutputTensor(node); + + return std::make_unique<kernels::Quantize>(input, output); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/ReduceMax.cpp b/compiler/luci-interpreter/src/loader/nodes/ReduceMax.cpp new file mode 100644 index 000000000..1a8522dd6 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/ReduceMax.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2022 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 "Builders.h" + +#include "kernels/ReduceMax.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleReduceMax(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleReduceMax *>(circle_node); + assert(node->arity() == 2); + + const Tensor *input = helper.getInputTensor(node->input()); + const Tensor *axes = helper.getInputTensor(node->reduction_indices()); + Tensor *output = helper.getOutputTensor(node); + + auto temp_index_unique = + std::make_unique<Tensor>(DataType::S32, Shape({}), AffineQuantization{}, ""); + temp_index_unique->set_observable(false); + temp_index_unique->set_data_buffer(nullptr); + Tensor *temp_index = + helper.getRuntimeGraph(node->graph())->addTensor(std::move(temp_index_unique)); + + auto resolved_axes_unique = + std::make_unique<Tensor>(DataType::S32, Shape({}), AffineQuantization{}, ""); + resolved_axes_unique->set_observable(false); + resolved_axes_unique->set_data_buffer(nullptr); + Tensor *resolved_axes = + helper.getRuntimeGraph(node->graph())->addTensor(std::move(resolved_axes_unique)); + + ReducerParams params{}; + params.keep_dims = node->keep_dims(); + + return std::make_unique<kernels::ReduceMax>(input, axes, output, temp_index, resolved_axes, + params); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/ReduceProd.cpp b/compiler/luci-interpreter/src/loader/nodes/ReduceProd.cpp new file mode 100644 index 000000000..1610e20a9 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/ReduceProd.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2023 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 "Builders.h" + +#include "kernels/ReduceProd.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleReduceProd(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleReduceProd *>(circle_node); + assert(node->arity() == 2); + + const Tensor *input = helper.getInputTensor(node->input()); + const Tensor *axes = helper.getInputTensor(node->reduction_indices()); + Tensor *output = helper.getOutputTensor(node); + + auto temp_index_unique = + std::make_unique<Tensor>(DataType::S32, Shape({}), AffineQuantization{}, ""); + temp_index_unique->set_observable(false); + temp_index_unique->set_data_buffer(nullptr); + Tensor *temp_index = + helper.getRuntimeGraph(node->graph())->addTensor(std::move(temp_index_unique)); + + auto resolved_axes_unique = + std::make_unique<Tensor>(DataType::S32, Shape({}), AffineQuantization{}, ""); + resolved_axes_unique->set_observable(false); + resolved_axes_unique->set_data_buffer(nullptr); + Tensor *resolved_axes = + helper.getRuntimeGraph(node->graph())->addTensor(std::move(resolved_axes_unique)); + + ReducerParams params{}; + params.keep_dims = node->keep_dims(); + + return std::make_unique<kernels::ReduceProd>(input, axes, output, temp_index, resolved_axes, + params); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/Relu.cpp b/compiler/luci-interpreter/src/loader/nodes/Relu.cpp new file mode 100644 index 000000000..1d64c1c4e --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Relu.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/Relu.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleRelu(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleRelu *>(circle_node); + assert(node->arity() == 1); + + const Tensor *input = helper.getInputTensor(node->features()); + Tensor *output = helper.getOutputTensor(node); + + return std::make_unique<kernels::Relu>(input, output); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/Relu6.cpp b/compiler/luci-interpreter/src/loader/nodes/Relu6.cpp new file mode 100644 index 000000000..e50cd2545 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Relu6.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/Relu6.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleRelu6(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleRelu6 *>(circle_node); + assert(node->arity() == 1); + + const Tensor *input = helper.getInputTensor(node->features()); + Tensor *output = helper.getOutputTensor(node); + + return std::make_unique<kernels::Relu6>(input, output); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/Reshape.cpp b/compiler/luci-interpreter/src/loader/nodes/Reshape.cpp new file mode 100644 index 000000000..76ddd88a3 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Reshape.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/Reshape.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleReshape(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleReshape *>(circle_node); + assert(node->arity() == 2); + + const Tensor *input = helper.getInputTensor(node->tensor()); + const Tensor *shape = helper.getInputTensor(node->shape()); + Tensor *output = helper.getOutputTensor(node); + + // NOTE 'newShape' attribute is ignored. + return std::make_unique<kernels::Reshape>(input, shape, output); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/ResizeBilinear.cpp b/compiler/luci-interpreter/src/loader/nodes/ResizeBilinear.cpp new file mode 100644 index 000000000..dc2b88ad3 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/ResizeBilinear.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/ResizeBilinear.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleResizeBilinear(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleResizeBilinear *>(circle_node); + assert(node->arity() == 2); + + const Tensor *input = helper.getInputTensor(node->input()); + const Tensor *size = helper.getInputTensor(node->size()); + Tensor *output = helper.getOutputTensor(node); + + ResizeBilinearParams params{}; + params.align_corners = node->align_corners(); + params.half_pixel_centers = node->half_pixel_centers(); + + return std::make_unique<kernels::ResizeBilinear>(input, size, output, params); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/ResizeNearestNeighbor.cpp b/compiler/luci-interpreter/src/loader/nodes/ResizeNearestNeighbor.cpp new file mode 100644 index 000000000..c7058ae78 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/ResizeNearestNeighbor.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/ResizeNearestNeighbor.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> +build_kernel_CircleResizeNearestNeighbor(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleResizeNearestNeighbor *>(circle_node); + assert(node->arity() == 2); + + const Tensor *input = helper.getInputTensor(node->input()); + const Tensor *size = helper.getInputTensor(node->size()); + Tensor *output = helper.getOutputTensor(node); + + ResizeNearestNeighborParams params{}; + params.align_corners = node->align_corners(); + // TODO update half_pixel_centers after CircleResizeNearestNeighbor updated + // Current CircleResizeNearestNeighbor don't have half_pixel_centers. + // default value on current is false. + // it need to be updated when CircleResizeNearestNeighbor updated. + params.half_pixel_centers = false; + + return std::make_unique<kernels::ResizeNearestNeighbor>(input, size, output, params); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/ReverseV2.cpp b/compiler/luci-interpreter/src/loader/nodes/ReverseV2.cpp new file mode 100644 index 000000000..c1a7f5350 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/ReverseV2.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/ReverseV2.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleReverseV2(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleReverseV2 *>(circle_node); + assert(node->arity() == 2); + + const Tensor *input = helper.getInputTensor(node->tensor()); + const Tensor *axes = helper.getInputTensor(node->axis()); + Tensor *output = helper.getOutputTensor(node); + + return std::make_unique<kernels::ReverseV2>(input, axes, output); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/Rsqrt.cpp b/compiler/luci-interpreter/src/loader/nodes/Rsqrt.cpp new file mode 100644 index 000000000..0714a5dba --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Rsqrt.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/Rsqrt.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleRsqrt(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleRsqrt *>(circle_node); + assert(node->arity() == 1); + + const Tensor *input = helper.getInputTensor(node->x()); + Tensor *output = helper.getOutputTensor(node); + + return std::make_unique<kernels::Rsqrt>(input, output); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/SVDF.cpp b/compiler/luci-interpreter/src/loader/nodes/SVDF.cpp new file mode 100644 index 000000000..d172ef438 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/SVDF.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2022 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 "Builders.h" + +#include "kernels/SVDF.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleSVDF(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleSVDF *>(circle_node); + assert(node->arity() == 5); + + const Tensor *input = helper.getInputTensor(node->input()); + const Tensor *feature = helper.getInputTensor(node->weight_feature()); + const Tensor *time = helper.getInputTensor(node->weight_time()); + const Tensor *bias = helper.getOptionalInputTensor(node->bias()); + const Tensor *input_activation_state = helper.getInputTensor(node->input_activation_state()); + Tensor *output = helper.getOutputTensor(node); + + auto scratchpad_tensor = std::make_unique<Tensor>(input_activation_state->element_type(), + Shape({}), AffineQuantization{}, ""); + scratchpad_tensor->set_observable(false); + scratchpad_tensor->set_data_buffer(nullptr); + Tensor *tmp = helper.getRuntimeGraph(node->graph())->addTensor(std::move(scratchpad_tensor)); + + DataType data_type = input->element_type() == DataType::S8 ? DataType::S32 : DataType::FLOAT32; + + scratchpad_tensor = std::make_unique<Tensor>(data_type, Shape({}), AffineQuantization{}, ""); + scratchpad_tensor->set_observable(false); + scratchpad_tensor->set_data_buffer(nullptr); + Tensor *tmp_1 = helper.getRuntimeGraph(node->graph())->addTensor(std::move(scratchpad_tensor)); + + if (data_type == DataType::FLOAT32 && + (feature->element_type() == DataType::S8 || feature->element_type() == DataType::U8)) + { + data_type = feature->element_type(); + } + + scratchpad_tensor = std::make_unique<Tensor>(data_type, Shape({}), AffineQuantization{}, ""); + scratchpad_tensor->set_observable(false); + scratchpad_tensor->set_data_buffer(nullptr); + Tensor *tmp_2 = helper.getRuntimeGraph(node->graph())->addTensor(std::move(scratchpad_tensor)); + + data_type = DataType::FLOAT32; + + scratchpad_tensor = std::make_unique<Tensor>(data_type, Shape({}), AffineQuantization{}, ""); + scratchpad_tensor->set_observable(false); + scratchpad_tensor->set_data_buffer(nullptr); + Tensor *tmp_3 = helper.getRuntimeGraph(node->graph())->addTensor(std::move(scratchpad_tensor)); + + scratchpad_tensor = std::make_unique<Tensor>(data_type, Shape({}), AffineQuantization{}, ""); + scratchpad_tensor->set_observable(false); + scratchpad_tensor->set_data_buffer(nullptr); + Tensor *tmp_4 = helper.getRuntimeGraph(node->graph())->addTensor(std::move(scratchpad_tensor)); + + scratchpad_tensor = std::make_unique<Tensor>(data_type, Shape({}), AffineQuantization{}, ""); + scratchpad_tensor->set_observable(false); + scratchpad_tensor->set_data_buffer(nullptr); + Tensor *tmp_5 = helper.getRuntimeGraph(node->graph())->addTensor(std::move(scratchpad_tensor)); + + scratchpad_tensor = std::make_unique<Tensor>(data_type, Shape({}), AffineQuantization{}, ""); + scratchpad_tensor->set_observable(false); + scratchpad_tensor->set_data_buffer(nullptr); + Tensor *tmp_6 = helper.getRuntimeGraph(node->graph())->addTensor(std::move(scratchpad_tensor)); + + SVDFParams params{}; + params.activation = node->fusedActivationFunction(); + params.svdf_rank = node->svdf_rank(); + params.asymmetric_quantize_inputs = node->asymmetric_quantize_inputs(); + + return std::make_unique<kernels::SVDF>(input, feature, time, bias, input_activation_state, output, + tmp, tmp_1, tmp_2, tmp_3, tmp_4, tmp_5, tmp_6, params); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/Select.cpp b/compiler/luci-interpreter/src/loader/nodes/Select.cpp new file mode 100644 index 000000000..a0f18047b --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Select.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2023 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 "Builders.h" + +#include "kernels/Select.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleSelect(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleSelect *>(circle_node); + assert(node->arity() == 3); + + const Tensor *c = helper.getInputTensor(node->condition()); + const Tensor *t = helper.getInputTensor(node->t()); + const Tensor *e = helper.getInputTensor(node->e()); + Tensor *output = helper.getOutputTensor(node); + + return std::make_unique<kernels::Select>(c, t, e, output); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/Shape.cpp b/compiler/luci-interpreter/src/loader/nodes/Shape.cpp new file mode 100644 index 000000000..d1edbc794 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Shape.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2022 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 "Builders.h" + +#include "kernels/Shape.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleShape(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleShape *>(circle_node); + assert(node->arity() == 1); + + const auto input = helper.getInputTensor(node->input()); + auto output = helper.getOutputTensor(node); + + ShapeParams shape_params{}; + shape_params.out_type = node->out_type(); + + return std::make_unique<kernels::ShapeKernel>(input, output, shape_params); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/Slice.cpp b/compiler/luci-interpreter/src/loader/nodes/Slice.cpp new file mode 100644 index 000000000..60ac6417c --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Slice.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/Slice.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleSlice(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleSlice *>(circle_node); + assert(node->arity() == 3); + + const Tensor *input = helper.getInputTensor(node->input()); + const Tensor *begin = helper.getInputTensor(node->begin()); + const Tensor *size = helper.getInputTensor(node->size()); + + Tensor *output = helper.getOutputTensor(node); + + return std::make_unique<kernels::Slice>(input, begin, size, output); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/Softmax.cpp b/compiler/luci-interpreter/src/loader/nodes/Softmax.cpp new file mode 100644 index 000000000..f41f63f6f --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Softmax.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/Softmax.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleSoftmax(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleSoftmax *>(circle_node); + assert(node->arity() == 1); + + const Tensor *input = helper.getInputTensor(node->logits()); + Tensor *output = helper.getOutputTensor(node); + + SoftmaxParams params{}; + params.beta = node->beta(); + + return std::make_unique<kernels::Softmax>(input, output, params); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/SpaceToBatchND.cpp b/compiler/luci-interpreter/src/loader/nodes/SpaceToBatchND.cpp new file mode 100644 index 000000000..b6e6cf516 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/SpaceToBatchND.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/SpaceToBatchND.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleSpaceToBatchND(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleSpaceToBatchND *>(circle_node); + assert(node->arity() == 3); + + const Tensor *input = helper.getInputTensor(node->input()); + const Tensor *block_shape = helper.getInputTensor(node->block_shape()); + const Tensor *paddings = helper.getInputTensor(node->paddings()); + + Tensor *output = helper.getOutputTensor(node); + + return std::make_unique<kernels::SpaceToBatchND>(input, block_shape, paddings, output); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/SpaceToDepth.cpp b/compiler/luci-interpreter/src/loader/nodes/SpaceToDepth.cpp new file mode 100644 index 000000000..63fdb95ec --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/SpaceToDepth.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/SpaceToDepth.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleSpaceToDepth(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleSpaceToDepth *>(circle_node); + assert(node->arity() == 1); + const Tensor *input = helper.getInputTensor(node->input()); + + Tensor *output = helper.getOutputTensor(node); + + SpaceToDepthParams params{}; + params.block_size = node->block_size(); + + return std::make_unique<kernels::SpaceToDepth>(input, output, params); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/Split.cpp b/compiler/luci-interpreter/src/loader/nodes/Split.cpp new file mode 100644 index 000000000..3f6d4a7df --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Split.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/Split.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleSplit(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleSplit *>(circle_node); + auto output_nodes = collectOutputNodes<luci::CircleSplitOut>(node); + assert(node->arity() == 2); + assert(output_nodes.size() == static_cast<size_t>(node->num_split())); + + const Tensor *axis = helper.getInputTensor(node->split_dim()); + const Tensor *input = helper.getInputTensor(node->input()); + std::vector<Tensor *> outputs = helper.getOutputTensors(output_nodes); + + // NOTE 'num_splits' attribute is ignored. + return std::make_unique<kernels::Split>(axis, input, std::move(outputs)); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/SplitV.cpp b/compiler/luci-interpreter/src/loader/nodes/SplitV.cpp new file mode 100644 index 000000000..0788822ca --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/SplitV.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/SplitV.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleSplitV(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleSplitV *>(circle_node); + auto output_nodes = collectOutputNodes<luci::CircleSplitVOut>(node); + assert(node->arity() == 3); + assert(output_nodes.size() == static_cast<size_t>(node->num_split())); + + const Tensor *input = helper.getInputTensor(node->input()); + const Tensor *sizes_data = helper.getInputTensor(node->size_splits()); + const Tensor *axis = helper.getInputTensor(node->split_dim()); + std::vector<Tensor *> outputs = helper.getOutputTensors(output_nodes); + + // NOTE 'num_splits' attribute is ignored. + return std::make_unique<kernels::SplitV>(input, sizes_data, axis, std::move(outputs)); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/Sqrt.cpp b/compiler/luci-interpreter/src/loader/nodes/Sqrt.cpp new file mode 100644 index 000000000..b9843fe0b --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Sqrt.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/Sqrt.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleSqrt(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleSqrt *>(circle_node); + assert(node->arity() == 1); + + const Tensor *input = helper.getInputTensor(node->x()); + Tensor *output = helper.getOutputTensor(node); + + return std::make_unique<kernels::Sqrt>(input, output); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/Square.cpp b/compiler/luci-interpreter/src/loader/nodes/Square.cpp new file mode 100644 index 000000000..0ad7c1772 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Square.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/Square.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleSquare(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleSquare *>(circle_node); + assert(node->arity() == 1); + + const Tensor *input = helper.getInputTensor(node->x()); + Tensor *output = helper.getOutputTensor(node); + + return std::make_unique<kernels::Square>(input, output); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/SquaredDifference.cpp b/compiler/luci-interpreter/src/loader/nodes/SquaredDifference.cpp new file mode 100644 index 000000000..e4c6fd851 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/SquaredDifference.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/SquaredDifference.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleSquaredDifference(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleSquaredDifference *>(circle_node); + assert(node->arity() == 2); + + const Tensor *input1 = helper.getInputTensor(node->x()); + const Tensor *input2 = helper.getInputTensor(node->y()); + Tensor *output = helper.getOutputTensor(node); + + return std::make_unique<kernels::SquaredDifference>(input1, input2, output); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/Squeeze.cpp b/compiler/luci-interpreter/src/loader/nodes/Squeeze.cpp new file mode 100644 index 000000000..6885f8077 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Squeeze.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/Squeeze.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleSqueeze(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleSqueeze *>(circle_node); + assert(node->arity() == 1); + + const Tensor *input = helper.getInputTensor(node->input()); + Tensor *output = helper.getOutputTensor(node); + + SqueezeParams params{}; + params.squeeze_dims = node->squeeze_dims(); + + return std::make_unique<kernels::Squeeze>(input, output, params); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/StridedSlice.cpp b/compiler/luci-interpreter/src/loader/nodes/StridedSlice.cpp new file mode 100644 index 000000000..359b4e3e9 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/StridedSlice.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/StridedSlice.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleStridedSlice(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleStridedSlice *>(circle_node); + assert(node->arity() == 4); + + const Tensor *input = helper.getInputTensor(node->input()); + const Tensor *begin = helper.getInputTensor(node->begin()); + const Tensor *end = helper.getInputTensor(node->end()); + const Tensor *strides = helper.getInputTensor(node->strides()); + + Tensor *output = helper.getOutputTensor(node); + + StridedSliceParams params{}; + params.begin_mask = node->begin_mask(); + params.ellipsis_mask = node->ellipsis_mask(); + params.end_mask = node->end_mask(); + params.new_axis_mask = node->new_axis_mask(); + params.shrink_axis_mask = node->shrink_axis_mask(); + + return std::make_unique<kernels::StridedSlice>(input, begin, end, strides, output, params); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/Sub.cpp b/compiler/luci-interpreter/src/loader/nodes/Sub.cpp new file mode 100644 index 000000000..a6252cb53 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Sub.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/Sub.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleSub(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleSub *>(circle_node); + assert(node->arity() == 2); + + const Tensor *input1 = helper.getInputTensor(node->x()); + const Tensor *input2 = helper.getInputTensor(node->y()); + Tensor *output = helper.getOutputTensor(node); + + SubParams params{}; + params.activation = node->fusedActivationFunction(); + + return std::make_unique<kernels::Sub>(input1, input2, output, params); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/Sum.cpp b/compiler/luci-interpreter/src/loader/nodes/Sum.cpp new file mode 100644 index 000000000..6dfe362c9 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Sum.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2023 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 "Builders.h" + +#include "kernels/Sum.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleSum(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleSum *>(circle_node); + assert(node->arity() == 2); + + const Tensor *input = helper.getInputTensor(node->input()); + const Tensor *axes = helper.getInputTensor(node->reduction_indices()); + Tensor *output = helper.getOutputTensor(node); + + auto temp_index_unique = + std::make_unique<Tensor>(DataType::S32, Shape({}), AffineQuantization{}, ""); + temp_index_unique->set_observable(false); + temp_index_unique->set_data_buffer(nullptr); + Tensor *temp_index = + helper.getRuntimeGraph(node->graph())->addTensor(std::move(temp_index_unique)); + + auto resolved_axes_unique = + std::make_unique<Tensor>(DataType::S32, Shape({}), AffineQuantization{}, ""); + resolved_axes_unique->set_observable(false); + resolved_axes_unique->set_data_buffer(nullptr); + Tensor *resolved_axes = + helper.getRuntimeGraph(node->graph())->addTensor(std::move(resolved_axes_unique)); + + ReducerParams params{}; + params.keep_dims = node->keep_dims(); + + return std::make_unique<kernels::Sum>(input, axes, output, temp_index, resolved_axes, params); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/Tanh.cpp b/compiler/luci-interpreter/src/loader/nodes/Tanh.cpp new file mode 100644 index 000000000..a58ef60a8 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Tanh.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/Tanh.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleTanh(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleTanh *>(circle_node); + assert(node->arity() == 1); + + const Tensor *input = helper.getInputTensor(node->x()); + Tensor *output = helper.getOutputTensor(node); + + return std::make_unique<kernels::Tanh>(input, output); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/Transpose.cpp b/compiler/luci-interpreter/src/loader/nodes/Transpose.cpp new file mode 100644 index 000000000..ea17d8311 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Transpose.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/Transpose.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleTranspose(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleTranspose *>(circle_node); + assert(node->arity() == 2); + + const Tensor *input = helper.getInputTensor(node->a()); + const Tensor *perm = helper.getInputTensor(node->perm()); + Tensor *output = helper.getOutputTensor(node); + + return std::make_unique<kernels::Transpose>(input, perm, output); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/TransposeConv.cpp b/compiler/luci-interpreter/src/loader/nodes/TransposeConv.cpp new file mode 100644 index 000000000..72d1aecf7 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/TransposeConv.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/TransposeConv.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleTransposeConv(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleTransposeConv *>(circle_node); + assert(node->arity() == 4); + + const Tensor *input_sizes = helper.getInputTensor(node->inputSizes()); + const Tensor *filter = helper.getInputTensor(node->filter()); + const Tensor *out_backprop = helper.getInputTensor(node->outBackprop()); + const Tensor *bias = helper.getOptionalInputTensor(node->bias()); + + Tensor *output = helper.getOutputTensor(node); + + DataType scratch_data_type = + helper.getInputTensor(node)->element_type() == DataType::S16 ? DataType::S64 : DataType::S32; + + auto scratch_tensor = + std::make_unique<Tensor>(scratch_data_type, Shape({}), AffineQuantization{}, ""); + scratch_tensor->set_observable(false); + scratch_tensor->set_data_buffer(nullptr); + Tensor *tmp = helper.getRuntimeGraph(node->graph())->addTensor(std::move(scratch_tensor)); + + TransposeConvParams params{}; + params.padding = node->padding(); + params.stride_height = node->stride()->h(); + params.stride_width = node->stride()->w(); + params.activation = node->fusedActivationFunction(); + + // TODO support activation + if (params.activation != luci::FusedActFunc::NONE) + { + throw std::runtime_error("Unsupported activation of TransposeConv"); + } + + return std::make_unique<kernels::TransposeConv>(input_sizes, filter, out_backprop, bias, output, + tmp, params); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/UnidirectionalSequenceLSTM.cpp b/compiler/luci-interpreter/src/loader/nodes/UnidirectionalSequenceLSTM.cpp new file mode 100644 index 000000000..f4cf0b869 --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/UnidirectionalSequenceLSTM.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2022 Samsung Electronics Co., Ltd. All Rights Reserved + * Copyright 2017 The TensorFlow Authors. 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 "Builders.h" + +#include "kernels/UnidirectionalSequenceLSTM.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> +build_kernel_CircleUnidirectionalSequenceLSTM(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleUnidirectionalSequenceLSTM *>(circle_node); + assert(node->arity() == 24); + + const Tensor *input = helper.getInputTensor(node->input()); + const Tensor *input_to_input_weights = + helper.getOptionalInputTensor(node->input_to_input_weights()); + const Tensor *input_to_cell_weights = helper.getInputTensor(node->input_to_cell_weights()); + const Tensor *input_to_forget_weights = helper.getInputTensor(node->input_to_forget_weights()); + const Tensor *input_to_output_weights = helper.getInputTensor(node->input_to_output_weights()); + const Tensor *recurrent_to_input_weights = + helper.getOptionalInputTensor(node->recurrent_to_input_weights()); + const Tensor *recurrent_to_cell_weights = + helper.getInputTensor(node->recurrent_to_cell_weights()); + const Tensor *recurrent_to_forget_weights = + helper.getInputTensor(node->recurrent_to_forget_weights()); + const Tensor *recurrent_to_output_weights = + helper.getInputTensor(node->recurrent_to_output_weights()); + const Tensor *cell_to_input_weights = + helper.getOptionalInputTensor(node->cell_to_input_weights()); + const Tensor *cell_to_forget_weights = + helper.getOptionalInputTensor(node->cell_to_forget_weights()); + const Tensor *cell_to_output_weights = + helper.getOptionalInputTensor(node->cell_to_output_weights()); + const Tensor *input_gate_bias = helper.getOptionalInputTensor(node->input_gate_bias()); + const Tensor *forget_gate_bias = helper.getInputTensor(node->forget_gate_bias()); + const Tensor *cell_gate_bias = helper.getInputTensor(node->cell_gate_bias()); + const Tensor *output_gate_bias = helper.getInputTensor(node->output_gate_bias()); + const Tensor *projection_weights = helper.getOptionalInputTensor(node->projection_weights()); + const Tensor *projection_bias = helper.getOptionalInputTensor(node->projection_bias()); + const Tensor *output_state = helper.getInputTensor(node->output_state()); + const Tensor *cell_state = helper.getInputTensor(node->cell_state()); + const Tensor *input_layer_norm_coefficients = + helper.getOptionalInputTensor(node->input_layer_norm_coefficients()); + const Tensor *forget_layer_norm_coefficients = + helper.getOptionalInputTensor(node->forget_layer_norm_coefficients()); + const Tensor *cell_layer_norm_coefficients = + helper.getOptionalInputTensor(node->cell_layer_norm_coefficients()); + const Tensor *output_layer_norm_coefficients = + helper.getOptionalInputTensor(node->output_layer_norm_coefficients()); + Tensor *output = helper.getOutputTensor(node); + + // scratch pad tensor + // NOTE provide more scratch pads if support hybrid or integer + auto sp_output_state = + std::make_unique<Tensor>(output_state->element_type(), Shape({}), AffineQuantization{}, ""); + sp_output_state->set_observable(false); + sp_output_state->set_data_buffer(nullptr); + Tensor *tmp_1 = helper.getRuntimeGraph(node->graph())->addTensor(std::move(sp_output_state)); + + auto sp_cell_state = + std::make_unique<Tensor>(cell_state->element_type(), Shape({}), AffineQuantization{}, ""); + sp_cell_state->set_observable(false); + sp_cell_state->set_data_buffer(nullptr); + Tensor *tmp_2 = helper.getRuntimeGraph(node->graph())->addTensor(std::move(sp_cell_state)); + + auto sp_3 = std::make_unique<Tensor>(input->element_type(), Shape({}), AffineQuantization{}, ""); + sp_3->set_observable(false); + sp_3->set_data_buffer(nullptr); + Tensor *tmp_3 = helper.getRuntimeGraph(node->graph())->addTensor(std::move(sp_3)); + + UnidirectionalSequenceLSTMParams params{}; + params.activation = node->fusedActivationFunction(); + params.cell_clip = node->cell_clip(); + params.proj_clip = node->proj_clip(); + params.time_major = node->time_major(); + params.asymmetric_quantize_inputs = node->asymmetric_quantize_inputs(); + + return std::make_unique<kernels::UnidirectionalSequenceLSTM>( + input, input_to_input_weights, input_to_forget_weights, input_to_cell_weights, + input_to_output_weights, recurrent_to_input_weights, recurrent_to_forget_weights, + recurrent_to_cell_weights, recurrent_to_output_weights, cell_to_input_weights, + cell_to_forget_weights, cell_to_output_weights, input_gate_bias, forget_gate_bias, + cell_gate_bias, output_gate_bias, projection_weights, projection_bias, output_state, cell_state, + input_layer_norm_coefficients, forget_layer_norm_coefficients, cell_layer_norm_coefficients, + output_layer_norm_coefficients, output, tmp_1, tmp_2, tmp_3, params); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/Unpack.cpp b/compiler/luci-interpreter/src/loader/nodes/Unpack.cpp new file mode 100644 index 000000000..a1c0d323a --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/Unpack.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/Unpack.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleUnpack(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleUnpack *>(circle_node); + auto output_nodes = collectOutputNodes<luci::CircleUnpackOut>(node); + assert(node->arity() == 1); + assert(output_nodes.size() == static_cast<size_t>(node->num())); + + const Tensor *input = helper.getInputTensor(node->value()); + std::vector<Tensor *> outputs = helper.getOutputTensors(output_nodes); + + UnpackParams params{}; + params.axis = node->axis(); + + // NOTE 'num' attribute is ignored. + return std::make_unique<kernels::Unpack>(input, std::move(outputs), params); +} + +} // namespace luci_interpreter diff --git a/compiler/luci-interpreter/src/loader/nodes/While.cpp b/compiler/luci-interpreter/src/loader/nodes/While.cpp new file mode 100644 index 000000000..8fde6ec8a --- /dev/null +++ b/compiler/luci-interpreter/src/loader/nodes/While.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2021 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 "Builders.h" + +#include "kernels/While.h" + +namespace luci_interpreter +{ + +std::unique_ptr<Kernel> build_kernel_CircleWhile(const luci::CircleNode *circle_node, + KernelBuilderHelper &helper) +{ + const auto *node = loco::must_cast<const luci::CircleWhile *>(circle_node); + + auto output_nodes = collectOutputNodes<luci::CircleWhileOut>(node); + assert(node->arity() == node->input_count()); + assert(output_nodes.size() == static_cast<size_t>(node->output_count())); + + std::vector<const Tensor *> inputs(node->input_count()); + for (uint32_t i = 0; i < node->input_count(); ++i) + { + inputs[i] = helper.getInputTensor(node->input(i)); + } + std::vector<Tensor *> outputs = helper.getOutputTensors(output_nodes); + + RuntimeGraph *cond_graph = helper.getRuntimeGraph(node->cond_graph()); + RuntimeGraph *body_graph = helper.getRuntimeGraph(node->body_graph()); + + return std::make_unique<kernels::While>(std::move(inputs), std::move(outputs), cond_graph, + body_graph); +} + +} // namespace luci_interpreter |