diff options
Diffstat (limited to 'runtime/neurun/api/src')
-rw-r--r-- | runtime/neurun/api/src/CustomKernel.cc | 98 | ||||
-rw-r--r-- | runtime/neurun/api/src/CustomKernel.h | 59 | ||||
-rw-r--r-- | runtime/neurun/api/src/CustomKernelRegistry.cc | 64 | ||||
-rw-r--r-- | runtime/neurun/api/src/CustomKernelRegistry.h | 64 | ||||
-rw-r--r-- | runtime/neurun/api/src/OpMap.lst | 89 | ||||
-rw-r--r-- | runtime/neurun/api/src/nnfw_api.cc | 267 | ||||
-rw-r--r-- | runtime/neurun/api/src/nnfw_api_internal.cc | 435 | ||||
-rw-r--r-- | runtime/neurun/api/src/nnfw_api_internal.h | 84 | ||||
-rw-r--r-- | runtime/neurun/api/src/nnfw_debug.cc | 24 | ||||
-rw-r--r-- | runtime/neurun/api/src/nnfw_debug_internal.cc | 25 | ||||
-rw-r--r-- | runtime/neurun/api/src/nnfw_debug_internal.h | 29 |
11 files changed, 1238 insertions, 0 deletions
diff --git a/runtime/neurun/api/src/CustomKernel.cc b/runtime/neurun/api/src/CustomKernel.cc new file mode 100644 index 000000000..60ddeedc2 --- /dev/null +++ b/runtime/neurun/api/src/CustomKernel.cc @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "CustomKernel.h" + +namespace neurun +{ +namespace frontend +{ +namespace custom +{ + +using namespace backend::custom; + +class APIConverter +{ +public: + static nnfw_operand convertOperand(void *alloc, const TypeInfo &type) + { + nnfw_operand api_operand; + api_operand.allocation = alloc; + api_operand.type = convertType(type); + return api_operand; + } + + static nnfw_tensorinfo convertType(const TypeInfo &type) + { + nnfw_tensorinfo api_type; + api_type.rank = type.shape.rank(); + assert(type.shape.rank() <= 6); + std::copy(type.shape.dims().begin(), type.shape.dims().end(), std::begin(api_type.dims)); + + switch (type.dtype) + { + case ir::DataType::FLOAT32: + api_type.dtype = NNFW_TYPE_TENSOR_FLOAT32; + break; + case ir::DataType::INT32: + api_type.dtype = NNFW_TYPE_TENSOR_INT32; + break; + case ir::DataType::QUANT8_ASYMM: + api_type.dtype = NNFW_TYPE_TENSOR_QUANT8_ASYMM; + break; + case ir::DataType::BOOL8: + api_type.dtype = NNFW_TYPE_TENSOR_BOOL; + break; + default: + throw std::runtime_error("Unsupported tensor datatype"); + } + return api_type; + } +}; + +Kernel::Kernel(const nnfw_custom_eval evalFunction) + : _params(), _userdata(nullptr), _userdata_size(0), _evalFunction(evalFunction) +{ +} + +void Kernel::configure(CustomKernelConfigParams &&inParams) +{ + _userdata = inParams.userdata; + _userdata_size = inParams.userdata_size; + + _params.ninputs = inParams.input_allocations.size(); + _params.inputs = new nnfw_operand[_params.ninputs]; + for (size_t i = 0; i < _params.ninputs; ++i) + { + _params.inputs[i] = + APIConverter::convertOperand(inParams.input_allocations[i], inParams.input_types[i]); + } + + _params.noutputs = inParams.output_allocations.size(); + _params.outputs = new nnfw_operand[_params.noutputs]; + for (size_t i = 0; i < _params.noutputs; ++i) + { + _params.outputs[i] = + APIConverter::convertOperand(inParams.output_allocations[i], inParams.output_types[i]); + } +} + +void Kernel::run() { _evalFunction(&_params, _userdata, _userdata_size); } + +} // namespace custom +} // namespace backend +} // namespace neurun diff --git a/runtime/neurun/api/src/CustomKernel.h b/runtime/neurun/api/src/CustomKernel.h new file mode 100644 index 000000000..8cafc2061 --- /dev/null +++ b/runtime/neurun/api/src/CustomKernel.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __NEURUN_BACKEND_CUSTOM_KERNEL_H__ +#define __NEURUN_BACKEND_CUSTOM_KERNEL_H__ + +#include "nnfw_dev.h" + +#include "backend/CustomKernelBuilder.h" + +#include <vector> + +namespace neurun +{ +namespace frontend +{ +namespace custom +{ + +class Kernel : public ::neurun::exec::IFunction +{ +public: + explicit Kernel(nnfw_custom_eval evalFunction); + + nnfw_custom_kernel_params _params; + char *_userdata; + size_t _userdata_size; + + nnfw_custom_eval _evalFunction; + // nnfw_custom_type_infer _type_infer_function; //Unused for now + + /** + * Fills _params field used later by user specified eval function + * @param inParams custom kernel parameters + */ + virtual void configure(backend::custom::CustomKernelConfigParams &&inParams); + + void run() override; + void runSync() override { run(); } +}; + +} // namespace custom +} // namespace frontend +} // namespace neurun + +#endif // __NEURUN_BACKEND_CUSTOM_KERNEL_H__ diff --git a/runtime/neurun/api/src/CustomKernelRegistry.cc b/runtime/neurun/api/src/CustomKernelRegistry.cc new file mode 100644 index 000000000..b223682b8 --- /dev/null +++ b/runtime/neurun/api/src/CustomKernelRegistry.cc @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "CustomKernelRegistry.h" + +#include "cpp14/memory.h" + +namespace neurun +{ +namespace frontend +{ +namespace custom +{ + +void KernelRegistry::registerKernel(const std::string &id, nnfw_custom_eval evalFunction) +{ + _storage.emplace(id, evalFunction); +} + +std::shared_ptr<backend::custom::IKernelBuilder> KernelRegistry::getBuilder() +{ + return nnfw::cpp14::make_unique<KernelBuilder>(this); +} + +std::unique_ptr<Kernel> KernelRegistry::buildKernelForOp(const std::string &id) +{ + auto it = _storage.find(id); + if (it == _storage.end()) + { + throw std::runtime_error("Unable to find associated kernel for op"); + } + + return nnfw::cpp14::make_unique<Kernel>(it->second); +} + +// Kernel builder +std::unique_ptr<exec::IFunction> +KernelBuilder::buildKernel(const std::string &id, + backend::custom::CustomKernelConfigParams &¶ms) const +{ + auto kernel = _registry->buildKernelForOp(id); + kernel->configure(std::move(params)); + + return kernel; +} + +KernelBuilder::KernelBuilder(KernelRegistry *registry) : _registry(registry) {} + +} // namespace custom +} // namespace frontend +} // namespace neurun diff --git a/runtime/neurun/api/src/CustomKernelRegistry.h b/runtime/neurun/api/src/CustomKernelRegistry.h new file mode 100644 index 000000000..207a82a0a --- /dev/null +++ b/runtime/neurun/api/src/CustomKernelRegistry.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __NEURUN_BACKEND_CUSTOM_KERNEL_REGISTRY_H__ +#define __NEURUN_BACKEND_CUSTOM_KERNEL_REGISTRY_H__ + +#include "CustomKernel.h" + +#include <unordered_map> +#include <functional> +#include <memory> + +#include <iostream> + +namespace neurun +{ +namespace frontend +{ +namespace custom +{ + +class KernelRegistry +{ +public: + void registerKernel(const std::string &id, nnfw_custom_eval evalFunction); + + std::shared_ptr<backend::custom::IKernelBuilder> getBuilder(); + std::unique_ptr<Kernel> buildKernelForOp(const std::string &id); + +private: + std::unordered_map<std::string, nnfw_custom_eval> _storage; +}; + +class KernelBuilder : public backend::custom::IKernelBuilder +{ +public: + KernelBuilder(KernelRegistry *registry); + + std::unique_ptr<exec::IFunction> + buildKernel(const std::string &id, + backend::custom::CustomKernelConfigParams &¶ms) const override; + +private: + KernelRegistry *_registry; +}; + +} // namespace custom +} // namespace frontend +} // namespace neurun + +#endif // __NEURUN_BACKEND_CUSTOM_KERNEL_REGISTRY_H__ diff --git a/runtime/neurun/api/src/OpMap.lst b/runtime/neurun/api/src/OpMap.lst new file mode 100644 index 000000000..5e93275b8 --- /dev/null +++ b/runtime/neurun/api/src/OpMap.lst @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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 MAP_MACRO +#error Define MAP_MACRO before including this file +#endif + +// circle operation | neurun internal operation +MAP_MACRO(ADD , Add) +MAP_MACRO(SUB , Sub) +MAP_MACRO(BATCH_TO_SPACE_ND , BatchToSpaceND) +MAP_MACRO(CAST , Cast) +MAP_MACRO(CONV_2D , Conv2D) +MAP_MACRO(DEPTHWISE_CONV_2D , DepthwiseConv2D) +MAP_MACRO(AVERAGE_POOL_2D , AvgPool2D) +MAP_MACRO(MAX_POOL_2D , MaxPool2D) +MAP_MACRO(CONCATENATION , Concat) +MAP_MACRO(FULLY_CONNECTED , FullyConnected) +MAP_MACRO(SUM , ReduceSum) +MAP_MACRO(RESHAPE , Reshape) +MAP_MACRO(MUL , Mul) +MAP_MACRO(SOFTMAX , Softmax) +MAP_MACRO(SQUEEZE , Squeeze) +MAP_MACRO(SLICE , Slice) +MAP_MACRO(STRIDED_SLICE , StridedSlice) +MAP_MACRO(TANH , Tanh) +MAP_MACRO(LOGISTIC , Logistic) +MAP_MACRO(DIV , Div) +MAP_MACRO(TRANSPOSE , Transpose) +MAP_MACRO(EXP , Exp) +MAP_MACRO(REDUCE_MAX , ReduceMax) +// UNMATCHED +//MAP_MACRO(Comparison) +MAP_MACRO(LOGICAL_AND , LogicalAnd) +MAP_MACRO(LOGICAL_OR , LogicalOr) +MAP_MACRO(LOGICAL_NOT , LogicalNot) +MAP_MACRO(LSTM , LSTM) +MAP_MACRO(RSQRT , RSQRT) +MAP_MACRO(RELU , ReLU) +MAP_MACRO(RESIZE_BILINEAR , ResizeBilinear) +MAP_MACRO(RELU_N1_TO_1 , ReLU1) +MAP_MACRO(RELU6 , ReLU6) +MAP_MACRO(RNN , RNN) +MAP_MACRO(FLOOR , Floor) +MAP_MACRO(SPACE_TO_BATCH_ND , SpaceToBatchND) +MAP_MACRO(SPACE_TO_DEPTH , SpaceToDepth) +MAP_MACRO(L2_POOL_2D , L2Pool2D) +MAP_MACRO(EMBEDDING_LOOKUP , EmbeddingLookup) +MAP_MACRO(L2_NORMALIZATION , L2Normalization) +MAP_MACRO(HASHTABLE_LOOKUP , HashtableLookup) +MAP_MACRO(INSTANCE_NORM , InstanceNorm) +MAP_MACRO(PRELU , PReLU) +MAP_MACRO(TRANSPOSE_CONV , TransposeConv) +MAP_MACRO(SQRT , SQRT) +MAP_MACRO(SQUARED_DIFFERENCE , SquaredDifference) +MAP_MACRO(TOPK_V2 , TopKV2) +MAP_MACRO(GATHER , Gather) +MAP_MACRO(NEG , Neg) +MAP_MACRO(ABS , Abs) +MAP_MACRO(ARG_MAX , ArgMax) +MAP_MACRO(DEQUANTIZE , Dequantize) +MAP_MACRO(MEAN , Mean) +MAP_MACRO(LOCAL_RESPONSE_NORMALIZATION , LocalResponseNormalization) +// UNDEFINED IN CIRCLE +//MAP_MACRO(DepthToSpace) +MAP_MACRO(PACK , Pack) +MAP_MACRO(REDUCE_MIN , ReduceMin) +MAP_MACRO(SPLIT , Split) +MAP_MACRO(UNPACK , Unpack) +MAP_MACRO(PAD , Pad) +MAP_MACRO(CUSTOM , Custom) +// UNDEFINED IN CIRCLE +//MAP_MACRO(Permute) +MAP_MACRO(MINIMUM , Min) +MAP_MACRO(MAXIMUM , Max) +MAP_MACRO(ONE_HOT , OneHot) diff --git a/runtime/neurun/api/src/nnfw_api.cc b/runtime/neurun/api/src/nnfw_api.cc new file mode 100644 index 000000000..bdac4c89b --- /dev/null +++ b/runtime/neurun/api/src/nnfw_api.cc @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nnfw_api_internal.h" + +/* + * Create a new session instance + * + * @param session the session to be created + * @return NNFW_STATUS_NO_ERROR if successful + */ +NNFW_STATUS nnfw_create_session(nnfw_session **session) +{ + *session = new nnfw_session(); + + return NNFW_STATUS_NO_ERROR; +} + +/* + * Close a session instance + * + * @param session the session to be closed + * @return NNFW_STATUS_NO_ERROR if successful + */ +NNFW_STATUS nnfw_close_session(nnfw_session *session) +{ + delete session; + return NNFW_STATUS_NO_ERROR; +} + +#define NNFW_RETURN_ERROR_IF_NULL(p) \ + do \ + { \ + if ((p) == NULL) \ + return NNFW_STATUS_ERROR; \ + } while (0) + +/* + * Load model from nnpackage file or directory + * + * @param session nnfw_session loading the given nnpackage file/dir + * @param package_file_path path to the nnpackage file or unzipped directory to be loaded + * + * @return NNFW_STATUS_NO_ERROR if successful + */ +NNFW_STATUS nnfw_load_model_from_file(nnfw_session *session, const char *pacakge_file_path) +{ + NNFW_RETURN_ERROR_IF_NULL(session); + return session->load_model_from_file(pacakge_file_path); +} + +/* + * Prepare session to be ready for inference + * This phase may finalize model compilation, scheduling, and additional settings. + * + * @param session the session to be prepared + * @return NNFW_STATUS_NO_ERROR if successful + */ +NNFW_STATUS nnfw_prepare(nnfw_session *session) +{ + NNFW_RETURN_ERROR_IF_NULL(session); + return session->prepare(); +} + +/* + * Run inference + * + * @param session the session to run inference + * @return NNFW_STATUS_NO_ERROR if successful + */ +NNFW_STATUS nnfw_run(nnfw_session *session) +{ + NNFW_RETURN_ERROR_IF_NULL(session); + return session->run(); +} + +/* + * Set input + * + * @param session session to the input is to be set + * @param index index of input to be set (0-indexed) + * @param type type of the input + * @param buffer raw buffer for input + * @param length size of bytes of output + * + * @return NNFW_STATUS_NO_ERROR if successful + */ + +NNFW_STATUS nnfw_set_input(nnfw_session *session, uint32_t index, NNFW_TYPE type, + const void *buffer, size_t length) +{ + NNFW_RETURN_ERROR_IF_NULL(session); + return session->set_input(index, type, buffer, length); +} + +/* + * Set output + * + * @param session session from inference output is to be extracted + * @param index index of output to be set (0-indexed) + * @param type type of the output + * @param buffer raw buffer for output + * @param length size of bytes of output + * + * @return NNFW_STATUS_NO_ERROR if successful + */ + +NNFW_STATUS nnfw_set_output(nnfw_session *session, uint32_t index, NNFW_TYPE type, void *buffer, + size_t length) +{ + NNFW_RETURN_ERROR_IF_NULL(session); + return session->set_output(index, type, buffer, length); +} + +/* + * Get the number of inputs + * + * @param[in] session session from input information is to be extracted + * @param[out] number variable which the number of inputs is put into + * + * @return NNFW_STATUS_NO_ERROR if successful + */ + +NNFW_STATUS nnfw_input_size(nnfw_session *session, uint32_t *number) +{ + NNFW_RETURN_ERROR_IF_NULL(session); + return session->input_size(number); +} + +/* + * Get the number of outputs + * + * @param[in] session session from output information is to be extracted + * @param[out] number variable which the number of outputs is put into + * + * @return NNFW_STATUS_NO_ERROR if successful + */ +NNFW_STATUS nnfw_output_size(nnfw_session *session, uint32_t *number) +{ + NNFW_RETURN_ERROR_IF_NULL(session); + return session->output_size(number); +} + +/* + * Set the layout of an input + * @note The input that does not call this has NNFW_LAYOUT_CHANNELS_LAST layout + * + * @param[in] session session from inference input is to be extracted + * @param[in] index index of input to be set (0-indexed) + * @param[in] layout layout to set to target input + * + * @return NNFW_STATUS_NO_ERROR if successful + */ +NNFW_STATUS nnfw_set_input_layout(nnfw_session *session, uint32_t index, NNFW_LAYOUT layout) +{ + NNFW_RETURN_ERROR_IF_NULL(session); + return session->set_input_layout(index, layout); +} + +/* + * Set the layout of an output + * @note The output that does not call this has NNFW_LAYOUT_CHANNELS_LAST layout + * + * @param[in] session session from inference output is to be extracted + * @param[in] index index of output to be set (0-indexed) + * @param[in] layout layout to set to target output + * + * @return NNFW_STATUS_NO_ERROR if successful + */ +NNFW_STATUS nnfw_set_output_layout(nnfw_session *session, uint32_t index, NNFW_LAYOUT layout) +{ + NNFW_RETURN_ERROR_IF_NULL(session); + return session->set_output_layout(index, layout); +} + +/* + * Get i-th input tensor info + * + * @param[in] session session from input information is to be extracted + * @param[in] index index of input + * @param[out] tensor_info nnfw_tensor_info + * + * @return NNFW_STATUS_NO_ERROR if successful + */ +NNFW_STATUS nnfw_input_tensorinfo(nnfw_session *session, uint32_t index, + nnfw_tensorinfo *tensor_info) +{ + NNFW_RETURN_ERROR_IF_NULL(session); + return session->input_tensorinfo(index, tensor_info); +} + +/* + * Get i-th output tensor info + * + * @param[in] session session from output information is to be extracted + * @param[in] index index of output + * @param[out] tensor_info nnfw_tensor_info + * + * @return NNFW_STATUS_NO_ERROR if successful + */ +NNFW_STATUS nnfw_output_tensorinfo(nnfw_session *session, uint32_t index, + nnfw_tensorinfo *tensor_info) +{ + NNFW_RETURN_ERROR_IF_NULL(session); + return session->output_tensorinfo(index, tensor_info); +} + +/* + * Register custom operation + * @param session session to register this operation + * @param id operation id + * @param info registration info ( eval function, etc. ) + * @return NNFW_STATUS_NO_ERROR if successful + */ +NNFW_STATUS nnfw_register_custom_op_info(nnfw_session *session, const char *id, + custom_kernel_registration_info *info) +{ + NNFW_RETURN_ERROR_IF_NULL(session); + return session->register_custom_operation(id, info->eval_function); +} + +NNFW_STATUS nnfw_apply_tensorinfo(nnfw_session *session, uint32_t index, + nnfw_tensorinfo tensor_info) +{ + NNFW_RETURN_ERROR_IF_NULL(session); + return session->apply_tensorinfo(index, tensor_info); +} + +/* + * Set available backends + * + * @param[in] session session to which a avilable backends are set + * @param[in] backends available backends on which nnfw uses + */ +NNFW_STATUS nnfw_set_available_backends(nnfw_session *session, const char *backends) +{ + NNFW_RETURN_ERROR_IF_NULL(session); + return session->set_available_backends(backends); +} + +/* + * Set the operation's backend + * + * @param[in] session session to be modified + * @param[in] op operation to be set + * @param[in] backend bakcend on which operation run + * + * @return NNFW_STATUS_NO_ERROR if successful + */ +NNFW_STATUS nnfw_set_op_backend(nnfw_session *session, const char *op, const char *backend) +{ + NNFW_RETURN_ERROR_IF_NULL(session); + return session->set_op_backend(op, backend); +} diff --git a/runtime/neurun/api/src/nnfw_api_internal.cc b/runtime/neurun/api/src/nnfw_api_internal.cc new file mode 100644 index 000000000..037cd3bca --- /dev/null +++ b/runtime/neurun/api/src/nnfw_api_internal.cc @@ -0,0 +1,435 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nnfw_api_internal.h" +#include "CustomKernelRegistry.h" +#include "compiler/Compiler.h" +#include "exec/Execution.h" +#include "circle_loader.h" +#include "tflite_loader.h" +#include "json/json.h" +#include <fstream> +#include <iostream> +#include <string> +#include <dirent.h> +#include <util/ConfigSource.h> + +/* + * API does not accept string argument longer than max length below + */ +#define MAX_BACKEND_NAME_LENGTH 32 +#define MAX_OP_NAME_LENGTH 64 + +// Is null-terminating in length ? +static bool null_terminating(const char *str, uint32_t length) +{ + for (uint32_t i = 0; i < length; i++) + { + if (*(str + i) == '\0') + { + return true; + } + } + return false; +} + +static neurun::ir::Layout convertLayout(NNFW_LAYOUT layout) +{ + if (layout == NNFW_LAYOUT_CHANNELS_LAST) + { + return neurun::ir::Layout::NHWC; + } + else if (layout == NNFW_LAYOUT_CHANNELS_FIRST) + { + return neurun::ir::Layout::NCHW; + } + return neurun::ir::Layout::UNKNOWN; +} + +nnfw_session::nnfw_session() + : _graph{nullptr}, _execution{nullptr}, + _kernel_registry{std::make_shared<neurun::frontend::custom::KernelRegistry>()}, + _source{nnfw::cpp14::make_unique<neurun::util::GeneralConfigSource>()} +{ + // DO NOTHING +} + +NNFW_STATUS nnfw_session::load_model_from_file(const char *package_dir) +{ + // TODO : add support for zipped package file load + DIR *dir; + if (!(dir = opendir(package_dir))) + { + std::cerr << "invalid nnpackge directory: " << package_dir << std::endl; + return NNFW_STATUS_ERROR; + } + closedir(dir); + + try + { + std::string manifest_file_name(package_dir); + manifest_file_name += "/metadata/MANIFEST"; + std::ifstream mfs(manifest_file_name); + + // extract the filename of the first(index 0) model + // e.g. In MANIFEST file, { "models" : [ "firstmodel.tflite", "2nd.tflite" ] } + Json::Value root; + mfs >> root; + Json::Value models = root["models"]; + Json::Value model_types = root["model-types"]; + + auto model_file_path = package_dir + std::string("/") + models[0].asString(); // first model + auto model_type = model_types[0].asString(); // first model's type + if (model_type == "tflite") + { + _graph = neurun::tflite_loader::loadModel(model_file_path.c_str()); + } + else if (model_type == "circle") + { + _graph = neurun::circle_loader::loadModel(model_file_path.c_str()); + } + else + { + std::cerr << "Unsupported model type in MANIFEST" << std::endl; + return NNFW_STATUS_ERROR; + } + _graph->bindKernelBuilder(_kernel_registry->getBuilder()); + } + catch (const std::exception &e) + { + std::cerr << "Error during model loading : " << e.what() << std::endl; + return NNFW_STATUS_ERROR; + } + return NNFW_STATUS_NO_ERROR; +} + +NNFW_STATUS nnfw_session::prepare() +{ + // TODO : add additional setting routine(executor type, backend) + // Note that we assume acl_cl backend + + try + { + // config_source setting + using neurun::util::config_source; + config_source(std::move(_source)); + + auto compiler = nnfw::cpp14::make_unique<neurun::compiler::Compiler>(_graph); + compiler->compile(); + std::shared_ptr<neurun::exec::IExecutor> executor; + compiler->release(executor); + _execution = std::make_shared<neurun::exec::Execution>(executor); + } + catch (const std::exception &e) + { + std::cerr << "Error during model prepare : " << e.what() << std::endl; + return NNFW_STATUS_ERROR; + } + return NNFW_STATUS_NO_ERROR; +} + +NNFW_STATUS nnfw_session::run() +{ + try + { + _execution->execute(); + } + catch (const std::exception &e) + { + std::cerr << "Error during nnfw_session::run : " << e.what() << std::endl; + return NNFW_STATUS_ERROR; + } + return NNFW_STATUS_NO_ERROR; +} + +NNFW_STATUS nnfw_session::set_input(uint32_t index, NNFW_TYPE /*type*/, const void *buffer, + size_t length) +{ + try + { + _execution->setInput(neurun::ir::IOIndex(index), buffer, length); + } + catch (const std::exception &e) + { + std::cerr << "Error during nnfw_session::set_input : " << e.what() << std::endl; + return NNFW_STATUS_ERROR; + } + return NNFW_STATUS_NO_ERROR; +} + +NNFW_STATUS nnfw_session::set_output(uint32_t index, NNFW_TYPE /*type*/, void *buffer, + size_t length) +{ + try + { + _execution->setOutput(neurun::ir::IOIndex(index), buffer, length); + } + catch (const std::exception &e) + { + std::cerr << "Error during nnfw_session::set_output : " << e.what() << std::endl; + return NNFW_STATUS_ERROR; + } + return NNFW_STATUS_NO_ERROR; +} + +NNFW_STATUS nnfw_session::input_size(uint32_t *number) +{ + try + { + if (number == nullptr) + { + std::cerr << "Error during nnfw_session::input_size, number is null pointer." << std::endl; + return NNFW_STATUS_ERROR; + } + *number = _graph->getInputs().size(); + } + catch (const std::exception &e) + { + std::cerr << "Error during nnfw_session::input_size : " << e.what() << std::endl; + return NNFW_STATUS_ERROR; + } + return NNFW_STATUS_NO_ERROR; +} + +NNFW_STATUS nnfw_session::output_size(uint32_t *number) +{ + try + { + if (number == nullptr) + { + std::cerr << "Error during nnfw_session::output_size, number is null pointer." << std::endl; + return NNFW_STATUS_ERROR; + } + *number = _graph->getOutputs().size(); + } + catch (const std::exception &e) + { + std::cerr << "Error during nnfw_session::output_size" << e.what() << std::endl; + return NNFW_STATUS_ERROR; + } + return NNFW_STATUS_NO_ERROR; +} + +NNFW_STATUS nnfw_session::set_input_layout(uint32_t index, NNFW_LAYOUT layout) +{ + try + { + if (layout != NNFW_LAYOUT_NONE && layout != NNFW_LAYOUT_CHANNELS_FIRST && + layout != NNFW_LAYOUT_CHANNELS_LAST) + { + std::cerr << "Error during nnfw_session::set_input_layout, not supported layout" << std::endl; + return NNFW_STATUS_ERROR; + } + _execution->setInputLayout(neurun::ir::IOIndex(index), convertLayout(layout)); + } + catch (const std::exception &e) + { + std::cerr << "Error during nnfw_session::set_input_layout : " << e.what() << std::endl; + return NNFW_STATUS_ERROR; + } + return NNFW_STATUS_NO_ERROR; +} + +NNFW_STATUS nnfw_session::set_output_layout(uint32_t index, NNFW_LAYOUT layout) +{ + try + { + if (layout != NNFW_LAYOUT_NONE && layout != NNFW_LAYOUT_CHANNELS_FIRST && + layout != NNFW_LAYOUT_CHANNELS_LAST) + { + std::cerr << "Error during nnfw_session::set_output_layout, not supported layout" + << std::endl; + return NNFW_STATUS_ERROR; + } + _execution->setOutputLayout(neurun::ir::IOIndex(index), convertLayout(layout)); + } + catch (const std::exception &e) + { + std::cerr << "Error during nnfw_session::set_output_layout : " << e.what() << std::endl; + return NNFW_STATUS_ERROR; + } + return NNFW_STATUS_NO_ERROR; +} + +static NNFW_TYPE datatype_to_nnfw_dtype(neurun::ir::DataType dt) +{ + using neurun::ir::DataType; + switch (dt) + { + case DataType::FLOAT32: + return NNFW_TYPE_TENSOR_FLOAT32; + case DataType::INT32: + return NNFW_TYPE_TENSOR_INT32; + case DataType::QUANT8_ASYMM: + return NNFW_TYPE_TENSOR_QUANT8_ASYMM; + case DataType::BOOL8: + return NNFW_TYPE_TENSOR_BOOL; + case DataType::UINT8: + return NNFW_TYPE_TENSOR_UINT8; + case DataType::UINT32: + case DataType::QUANT8_SYMM: + default: + std::cerr << "Error: Model has type that runtime API does not support." << std::endl; + exit(-1); + } +} + +NNFW_STATUS nnfw_session::apply_tensorinfo(uint32_t /*index*/, nnfw_tensorinfo /*ti*/) +{ + std::cerr << "Error: NYI" << std::endl; + return NNFW_STATUS_ERROR; +} + +NNFW_STATUS nnfw_session::input_tensorinfo(uint32_t index, nnfw_tensorinfo *ti) +{ + try + { + if (ti == nullptr) + { + std::cerr << "Error during nnfw_session::input_tensorinfo, tensorinfo is null pointer." + << std::endl; + return NNFW_STATUS_ERROR; + } + if (index >= _graph->getInputs().size()) + { + std::cerr << "Error during nnfw_session::input_tensorinfo, index is out of range." + << std::endl; + return NNFW_STATUS_ERROR; + } + auto opidx = _graph->getInputs().at(index); + auto shape = _graph->operands().at(opidx).shape(); + ti->rank = shape.rank(); + for (int j = 0; j < ti->rank; ++j) + { + ti->dims[j] = shape.dim(j); + } + ti->dtype = datatype_to_nnfw_dtype(_graph->operands().at(opidx).typeInfo().type()); + } + catch (const std::exception &e) + { + std::cerr << "Error during nnfw_session::input_tensorinfo : " << e.what() << std::endl; + return NNFW_STATUS_ERROR; + } + return NNFW_STATUS_NO_ERROR; +} + +NNFW_STATUS nnfw_session::output_tensorinfo(uint32_t index, nnfw_tensorinfo *ti) +{ + try + { + if (ti == nullptr) + { + std::cerr << "Error during nnfw_session::output_tensorinfo, tensorinfo is null pointer." + << std::endl; + return NNFW_STATUS_ERROR; + } + if (index >= _graph->getOutputs().size()) + { + std::cerr << "Error during nnfw_session::output_tensorinfo, index is out of range." + << std::endl; + return NNFW_STATUS_ERROR; + } + auto opidx = _graph->getOutputs().at(index); + auto shape = _graph->operands().at(opidx).shape(); + ti->rank = shape.rank(); + for (int j = 0; j < ti->rank; ++j) + { + ti->dims[j] = shape.dim(j); + } + ti->dtype = datatype_to_nnfw_dtype(_graph->operands().at(opidx).typeInfo().type()); + } + catch (const std::exception &e) + { + std::cerr << "Error during nnfw_session::output_tensorinfo : " << e.what() << std::endl; + return NNFW_STATUS_ERROR; + } + return NNFW_STATUS_NO_ERROR; +} +NNFW_STATUS nnfw_session::register_custom_operation(const std::string &id, + nnfw_custom_eval eval_func) +{ + _kernel_registry->registerKernel(id, eval_func); + return NNFW_STATUS_NO_ERROR; +} + +static std::string get_op_backend_string(std::string op) +{ +#define MAP_MACRO(CircleName, NeurunName) {#CircleName, "OP_BACKEND_" #NeurunName}, + + static std::unordered_map<std::string, std::string> operation_map = { +#include "OpMap.lst" + }; + +#undef MAP_MACRO + + auto n = operation_map.find(op); + + if (n == operation_map.end()) + { + // this return value is handled by a caller to return error code + return std::string(""); + } + else + { + return n->second; + } +} + +NNFW_STATUS nnfw_session::set_available_backends(const char *backends) +{ + try + { + if (!backends || null_terminating(backends, MAX_BACKEND_NAME_LENGTH) == false) + { + return NNFW_STATUS_ERROR; + } + + _source->set("BACKENDS", backends); + } + catch (const std::exception &e) + { + std::cerr << "Error during nnfw_session::set_available_backends : " << e.what() << std::endl; + return NNFW_STATUS_ERROR; + } + return NNFW_STATUS_NO_ERROR; +} + +NNFW_STATUS nnfw_session::set_op_backend(const char *op, const char *backend) +{ + try + { + if (!op || !null_terminating(op, MAX_OP_NAME_LENGTH) || !backend || + !null_terminating(backend, MAX_BACKEND_NAME_LENGTH)) + { + return NNFW_STATUS_ERROR; + } + + auto key = get_op_backend_string(op); + + if (key.empty()) + { + return NNFW_STATUS_ERROR; + } + + _source->set(key, backend); + } + catch (const std::exception &e) + { + std::cerr << "Error during nnfw_session::set_op_backend : " << e.what() << std::endl; + return NNFW_STATUS_ERROR; + } + return NNFW_STATUS_NO_ERROR; +} diff --git a/runtime/neurun/api/src/nnfw_api_internal.h b/runtime/neurun/api/src/nnfw_api_internal.h new file mode 100644 index 000000000..40069cc55 --- /dev/null +++ b/runtime/neurun/api/src/nnfw_api_internal.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __API_NNFW_API_INTERNAL_H__ +#define __API_NNFW_API_INTERNAL_H__ + +#include "nnfw.h" +#include "nnfw_dev.h" + +#include <util/GeneralConfigSource.h> + +#include <string> +#include <memory> + +namespace neurun +{ +namespace frontend +{ +namespace custom +{ +class KernelRegistry; +} +} // namespace frontend +namespace exec +{ +class Execution; +} +namespace ir +{ +class Graph; +} // namespace ir +} // namespace neurun + +struct nnfw_session +{ +public: + nnfw_session(); + + NNFW_STATUS load_model_from_file(const char *package_file_path); + NNFW_STATUS prepare(); + NNFW_STATUS run(); + + NNFW_STATUS set_input(uint32_t index, NNFW_TYPE type, const void *buffer, size_t length); + NNFW_STATUS set_output(uint32_t index, NNFW_TYPE type, void *buffer, size_t length); + + NNFW_STATUS input_size(uint32_t *number); + NNFW_STATUS output_size(uint32_t *number); + + NNFW_STATUS set_input_layout(uint32_t index, NNFW_LAYOUT layout); + NNFW_STATUS set_output_layout(uint32_t index, NNFW_LAYOUT layout); + + NNFW_STATUS apply_tensorinfo(uint32_t index, nnfw_tensorinfo ti); + + NNFW_STATUS input_tensorinfo(uint32_t index, nnfw_tensorinfo *ti); + NNFW_STATUS output_tensorinfo(uint32_t index, nnfw_tensorinfo *ti); + + NNFW_STATUS register_custom_operation(const std::string &id, nnfw_custom_eval eval_func); + + NNFW_STATUS set_available_backends(const char *backends); + NNFW_STATUS set_op_backend(const char *op, const char *backend); + +private: + std::shared_ptr<neurun::ir::Graph> _graph; + std::shared_ptr<neurun::exec::Execution> _execution; + std::shared_ptr<neurun::frontend::custom::KernelRegistry> _kernel_registry; + +protected: + std::unique_ptr<neurun::util::GeneralConfigSource> _source; +}; + +#endif // __API_NNFW_API_INTERNAL_H__ diff --git a/runtime/neurun/api/src/nnfw_debug.cc b/runtime/neurun/api/src/nnfw_debug.cc new file mode 100644 index 000000000..4ea0a203f --- /dev/null +++ b/runtime/neurun/api/src/nnfw_debug.cc @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nnfw_debug_internal.h" + +NNFW_STATUS nnfw_create_debug_session(nnfw_session **session) +{ + *session = new nnfw_debug_session(); + + return NNFW_STATUS_NO_ERROR; +} diff --git a/runtime/neurun/api/src/nnfw_debug_internal.cc b/runtime/neurun/api/src/nnfw_debug_internal.cc new file mode 100644 index 000000000..778efbc5c --- /dev/null +++ b/runtime/neurun/api/src/nnfw_debug_internal.cc @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "nnfw_debug_internal.h" +#include "util/EnvConfigSource.h" + +#include <cpp14/memory.h> + +nnfw_debug_session::nnfw_debug_session() : nnfw_session() +{ + _source = nnfw::cpp14::make_unique<neurun::util::EnvConfigSource>(); +} diff --git a/runtime/neurun/api/src/nnfw_debug_internal.h b/runtime/neurun/api/src/nnfw_debug_internal.h new file mode 100644 index 000000000..f4984e7a1 --- /dev/null +++ b/runtime/neurun/api/src/nnfw_debug_internal.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __API_NNFW_DEBUG_INTERNAL_H__ +#define __API_NNFW_DEBUG_INTERNAL_H__ + +#include "nnfw_debug.h" +#include "nnfw_api_internal.h" + +class nnfw_debug_session : public nnfw_session +{ +public: + nnfw_debug_session(); +}; + +#endif // __API_NNFW_DEBUG_INTERNAL_H__ |