From 0286ee84fb4a8594b28222c61b9e27592c6f2d49 Mon Sep 17 00:00:00 2001 From: "jijoong.moon" Date: Fri, 3 Apr 2020 14:16:11 +0900 Subject: [PATCH] [API] Prototype of C API & test for Neural Network Model - Add C API to construct / destruct Neural Network Model object . ml_nnmodel_construct() . ml_nnmodel_destruct() - Add test cases **Self evaluation:** 1. Build test: [X]Passed [ ]Failed [ ]Skipped 2. Run test: [X]Passed [ ]Failed [ ]Skipped Signed-off-by: jijoong.moon --- api/capi/include/nntrainer.h | 91 +++++++++++++++++++++++++++++++ api/capi/include/platform/tizen_error.h | 37 +++++++++++++ api/capi/meson.build | 41 ++++++++++++++ api/capi/src/nntrainer.cpp | 96 +++++++++++++++++++++++++++++++++ api/meson.build | 3 ++ debian/control | 2 +- debian/nntrainer-dev.install | 1 + jni/Android.mk | 3 +- meson.build | 7 +++ meson_options.txt | 3 ++ packaging/nntrainer.spec | 2 + test/decayed_learning_rate/Training.ini | 42 --------------- test/meson.build | 11 ++++ test/tizen_capi/meson.build | 14 +++++ test/tizen_capi/unittest_tizen_capi.cpp | 60 +++++++++++++++++++++ 15 files changed, 369 insertions(+), 44 deletions(-) create mode 100644 api/capi/include/nntrainer.h create mode 100644 api/capi/include/platform/tizen_error.h create mode 100644 api/capi/meson.build create mode 100644 api/capi/src/nntrainer.cpp create mode 100644 api/meson.build delete mode 100644 test/decayed_learning_rate/Training.ini create mode 100644 test/meson.build create mode 100644 test/tizen_capi/meson.build create mode 100644 test/tizen_capi/unittest_tizen_capi.cpp diff --git a/api/capi/include/nntrainer.h b/api/capi/include/nntrainer.h new file mode 100644 index 0000000..4d2a2c3 --- /dev/null +++ b/api/capi/include/nntrainer.h @@ -0,0 +1,91 @@ +/** + * 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. + */ +/** + * @file nntrainer.h + * @date 02 April 2020 + * @brief NNTrainer C-API Header. + * This allows to construct and control NNTrainer Model. + * @see https://github.com/nnstreamer/nntrainer + * @author Jijoong Moon + * @bug No known bugs except for NYI items + */ + +#ifndef __TIZEN_MACHINELEARNING_NNTRAINER_H__ +#define __TIZEN_MACHINELEARNING_NNTRAINER_H__ + +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ +/** + * @addtogroup CAPI_ML_NNTRAINER_MODULE + * @{ + */ + +/** + * @brief A handle of an NNTrainer model. + * @since_tizen 5.5 + */ +typedef void *ml_nnmodel_h; + +/** + * @brief Enumeration for the error codes of NNTrainer. + * @since_tizen 5.5 + */ +typedef enum { + ML_ERROR_NONE = TIZEN_ERROR_NONE, /**< Success! */ + ML_ERROR_INVALID_PARAMETER = TIZEN_ERROR_INVALID_PARAMETER, /**< Invalid parameter */ + ML_ERROR_UNKNOWN = TIZEN_ERROR_UNKNOWN, /**< Unknown error */ + ML_ERROR_TIMED_OUT = TIZEN_ERROR_TIMED_OUT, /**< Time out */ + ML_ERROR_NOT_SUPPORTED = TIZEN_ERROR_NOT_SUPPORTED, /**< The feature is not supported */ + ML_ERROR_PERMISSION_DENIED = TIZEN_ERROR_PERMISSION_DENIED, /**< Permission denied */ + ML_ERROR_OUT_OF_MEMORY = TIZEN_ERROR_OUT_OF_MEMORY, /**< Out of memory (Since 6.0) */ + ML_ERROR_CANNOT_ASSIGN_ADDRESS = TIZEN_ERROR_CANNOT_ASSIGN_ADDRESS, /**< Cannot assign requested address */ + ML_ERROR_BAD_ADDRESS = TIZEN_ERROR_BAD_ADDRESS, /**< Bad Address */ +} ml_error_e; + +/** + * @brief Constructs the neural network model. + * @details Use this function to create Neural Netowrk Model. + * @since_tizen 5.5 + * @param[in] model The NNTrainer Model handler from the given description. + * @return @c 0 on success. Otherwise a negative error value. + * @retval #ML_ERROR_NONE Successful. + * @retval #ML_ERROR_CANNOT_ASSIGN_ADDRESS Cannot assign object. + */ +int ml_nnmodel_construct(ml_nnmodel_h *model); + +/** + * @brief Destructs the neural network model. + * @details Use this function to delete Neural Netowrk Model. + * @since_tizen 5.5 + * @param[in] model The NNTrainer model handler from the given description. + * @return @c 0 on success. Otherwise a negative error value. + * @retval #ML_ERROR_NONE Successful. + * @retval #ML_ERROR_INVALID_PARAMETER Invalid Parameter. + */ +int ml_nnmodel_destruct(ml_nnmodel_h model); + +/** + * @} + */ +#ifdef __cplusplus +} + +#endif /* __cplusplus */ +#endif /* __TIZEN_MACHINELEARNING_NNTRAINER_H__ */ diff --git a/api/capi/include/platform/tizen_error.h b/api/capi/include/platform/tizen_error.h new file mode 100644 index 0000000..fdd6d82 --- /dev/null +++ b/api/capi/include/platform/tizen_error.h @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + */ +/** + * @file tizen_error.h + * @date 03 April 2020 + * @brief C-API internal header emulating tizen_error.h for Non-Tizen platforms + * @see https://github.com/nnstreamer/nntrainer + * @author Jijoong Moon + * @bug No known bugs except for NYI items + */ + +#ifndef __NTZN_TIZEN_ERROR_H__ +#define __NTZN_TIZEN_ERROR_H__ + +#include +#define TIZEN_ERROR_NONE (0) +#define TIZEN_ERROR_INVALID_PARAMETER (-EINVAL) +#define TIZEN_ERROR_UNKNOWN (-1073741824LL) +#define TIZEN_ERROR_TIMED_OUT (TIZEN_ERROR_UNKNOWN + 1) +#define TIZEN_ERROR_NOT_SUPPORTED (TIZEN_ERROR_UNKNOWN + 2) +#define TIZEN_ERROR_PERMISSION_DENIED (-EACCES) +#define TIZEN_ERROR_OUT_OF_MEMORY (-ENOMEM) +#define TIZEN_ERROR_CANNOT_ASSIGN_ADDRESS (-EADDRNOTAVAIL) +#define TIZEN_ERROR_BAD_ADDRESS (-EFAULT) + +#endif /* __NTZN_TIZEN_ERROR_H__ */ diff --git a/api/capi/meson.build b/api/capi/meson.build new file mode 100644 index 0000000..7808de4 --- /dev/null +++ b/api/capi/meson.build @@ -0,0 +1,41 @@ +capi_inc = [] +capi_inc += include_directories('include') + +if not get_option('enable-tizen') + capi_inc += include_directories ('include/platform') +endif + +capi_src = [] +capi_src += join_paths(meson.current_source_dir(), 'src','nntrainer.cpp') + +capi_headers = [] +capi_headers += join_paths(meson.current_source_dir(), 'include', 'nntrainer.h') + +capi_deps = [ + nntrainer_dep +] + +shared_library('capi-nntrainer', + capi_src, + dependencies: capi_deps, + include_directories: capi_inc, + install: true, + install_dir: nntrainer_libdir, +) + +nntrainer_capi_lib = static_library('capi-nntrainer', + capi_src, + dependencies: capi_deps, + include_directories: capi_inc, + install: true, + install_dir: nntrainer_libdir, +) + +nntrainer_capi_dep = declare_dependency(link_with: nntrainer_capi_lib, + dependencies: capi_deps, + include_directories: capi_inc, +) + +install_headers( capi_headers, + subdir: 'nntrainer' +) diff --git a/api/capi/src/nntrainer.cpp b/api/capi/src/nntrainer.cpp new file mode 100644 index 0000000..4a1235c --- /dev/null +++ b/api/capi/src/nntrainer.cpp @@ -0,0 +1,96 @@ +/** + * 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. + */ +/** + * @file nntrainer.c + * @date 02 April 2020 + * @brief NNTrainer C-API Wrapper. + * This allows to construct and control NNTrainer Model. + * @see https://github.com/nnstreamer/nntrainer + * @author Jijoong Moon + * @bug No known bugs except for NYI items + */ + +#include +#include +#include "neuralnet.h" + +#define ML_NNTRAINER_MAGIC 0x777F888F + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + uint magic; + Network::NeuralNetwork *network; +} ml_nnmodel; + +#define ML_NNTRAINER_CHECK_MODEL_VALIDATION(nnmodel, model) \ + do { \ + if (!model) { \ + std::cerr << "Error: Invalid Parameter : model is Empty" << std::endl; \ + return ML_ERROR_INVALID_PARAMETER; \ + } \ + nnmodel = (ml_nnmodel *)model; \ + if (nnmodel->magic != ML_NNTRAINER_MAGIC) { \ + std::cerr << "Error: Invalid Parameter : nnmodel is invalid." << std::endl; \ + return ML_ERROR_INVALID_PARAMETER; \ + } \ + } while (0) + +/** + * @brief Function to create Network::NeuralNetwork object. + */ +static int nn_object(ml_nnmodel_h *model) { + int status = ML_ERROR_NONE; + ml_nnmodel *nnmodel = new ml_nnmodel; + nnmodel->magic = ML_NNTRAINER_MAGIC; + + *model = nnmodel; + + try { + nnmodel->network = new Network::NeuralNetwork(); + } catch (const char *e) { + std::cerr << "Error: heap exception: " << e << std::endl; + status = ML_ERROR_CANNOT_ASSIGN_ADDRESS; + delete nnmodel; + } + + return status; +} + +int ml_nnmodel_construct(ml_nnmodel_h *model) { + int status = ML_ERROR_NONE; + + status = nn_object(model); + return status; +} + +int ml_nnmodel_destruct(ml_nnmodel_h model) { + int status = ML_ERROR_NONE; + ml_nnmodel *nnmodel; + + ML_NNTRAINER_CHECK_MODEL_VALIDATION(nnmodel, model); + + Network::NeuralNetwork *NN; + NN = nnmodel->network; + NN->finalize(); + delete NN; + + return status; +} + +#ifdef __cplusplus +} +#endif diff --git a/api/meson.build b/api/meson.build new file mode 100644 index 0000000..b47dbb9 --- /dev/null +++ b/api/meson.build @@ -0,0 +1,3 @@ +if get_option('enable-capi') + subdir('capi') +endif diff --git a/debian/control b/debian/control index 47df55e..dac0d4a 100644 --- a/debian/control +++ b/debian/control @@ -6,7 +6,7 @@ Build-Depends: gcc-9 | gcc-8 | gcc-7 | gcc-6 | gcc-5 (>=5.4), pkg-config, cmake, ninja-build, meson (>=0.50), debhelper (>=9), libboost-dev, libopenblas-dev, libiniparser-dev, tensorflow-lite-dev, libjsoncpp-dev, libcurl3-gnutls-dev | libcurl4-gnutls-dev | libcurl3-openssl-dev | - libcurl4-openssl-dev | libcurl3-nns-dev | libcurl4-nns-dev + libcurl4-openssl-dev | libcurl3-nns-dev | libcurl4-nns-dev, libgtest-dev Standards-Version: 3.9.6 Homepage: https://github.com/nnstreamer/nntrainer diff --git a/debian/nntrainer-dev.install b/debian/nntrainer-dev.install index a75afc0..9572952 100644 --- a/debian/nntrainer-dev.install +++ b/debian/nntrainer-dev.install @@ -2,5 +2,6 @@ /usr/include/nntrainer/layers.h /usr/include/nntrainer/neuralnet.h /usr/include/nntrainer/tensor.h +/usr/include/nntrainer/nntrainer.h /usr/lib/*/pkgconfig/*.pc /usr/lib/*/*.a diff --git a/jni/Android.mk b/jni/Android.mk index f7e2832..b05d8f3 100644 --- a/jni/Android.mk +++ b/jni/Android.mk @@ -34,7 +34,8 @@ INIPARSER_SRCS := $(INIPARSER_ROOT)/src/iniparser.c \ INIPARSER_INCLUDES := $(INIPARSER_ROOT)/src LOCAL_ARM_NEON := true -LOCAL_CFLAGS += -pthread -fopenmp +LOCAL_CFLAGS += -pthread -fopenmp -fexceptions +LOCAL_CXXFLAGS += -std=c++11 -frtti -fexceptions LOCAL_LDFLAGS += -fuse-ld=bfd LOCAL_MODULE_TAGS := optional diff --git a/meson.build b/meson.build index 8044845..ea14b23 100644 --- a/meson.build +++ b/meson.build @@ -118,3 +118,10 @@ if get_option('enable-app') tflite_dep = dependency('tensorflow-lite', required: true) subdir('Applications') endif + +# Build api +subdir('api') + +if get_option('enable-test') + subdir('test') +endif diff --git a/meson_options.txt b/meson_options.txt index f16fc8e..25448d5 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -3,3 +3,6 @@ option('enable-blas', type: 'boolean', value: true) option('enable-app', type: 'boolean', value: true) option('install-app', type: 'boolean', value: true) option('use_gym', type: 'boolean', value: false) +option('enable-capi', type: 'boolean', value: true) +option('enable-test', type: 'boolean', value: true) + diff --git a/packaging/nntrainer.spec b/packaging/nntrainer.spec index 03e9d27..8a7399e 100644 --- a/packaging/nntrainer.spec +++ b/packaging/nntrainer.spec @@ -14,6 +14,7 @@ Source1001: nntrainer.manifest BuildRequires: meson >= 0.50.0 BuildRequires: openblas-devel BuildRequires: iniparser-devel +BuildRequires: gtest-devel # OpenAI interface @@ -85,6 +86,7 @@ DESTDIR=%{buildroot} ninja -C build %{?_smp_mflags} install %{_includedir}/nntrainer/layers.h %{_includedir}/nntrainer/neuralnet.h %{_includedir}/nntrainer/tensor.h +%{_includedir}/nntrainer/nntrainer.h %{_libdir}/*.a %{_libdir}/pkgconfig/nntrainer.pc diff --git a/test/decayed_learning_rate/Training.ini b/test/decayed_learning_rate/Training.ini deleted file mode 100644 index 70ed705..0000000 --- a/test/decayed_learning_rate/Training.ini +++ /dev/null @@ -1,42 +0,0 @@ -# Network Section : Network -[Network] -Type = NeuralNetwork # Network Type : Regression, KNN, NeuralNetwork -Layers = inputlayer \ - fc1layer \ - outputlayer #Layers of Neuralnetwork -Learning_rate = 0.7 # Learning Rate -Decay_rate=0.96 #for the decay_rate for the decayed learning rate -Decay_steps = 1000 #decay step for the exponential decayed learning rate -Epoch = 300 # Epoch -Optimizer = adam # Optimizer : sgd (stochastic gradien decent), - # adam (Adamtive Moment Estimation) -Activation = sigmoid # activation : sigmoid, tanh -Cost = msr # Cost(loss) function : msr (mean square root error) - # categorical ( for logistic regression ) -Model = "model.bin" # model path to save / read -minibatch = 1 # mini batch size -beta1 = 0.9 # beta 1 for adam -beta2 = 0.9999 # beta 2 for adam -epsilon = 1e-8 # epsilon for adam - -# Layer Section : Name -[inputlayer] -Type = InputLayer -Id = 0 # Layer Id -Height = 1 -Width = 128 # Input Layer Dimension -Bias_zero = true # Zero Bias - -[fc1layer] -Type = FullyConnectedLayer -Id = 1 -Height = 128 # Input Dimension ( = Weight Height ) -Width = 20 # Hidden Layer Dimension ( = Weight Width ) -Bias_zero = true - -[outputlayer] -Type = OutputLayer -Id = 3 -Height = 20 # Hidden Layer Dimension ( = Weight Height ) -Width = 3 # Output Layer Dimension ( = Weight Width ) -Bias_zero = true diff --git a/test/meson.build b/test/meson.build new file mode 100644 index 0000000..4f4d9d3 --- /dev/null +++ b/test/meson.build @@ -0,0 +1,11 @@ +gtest_dep = dependency('gtest', required: false) +if gtest_dep.found() + nntrainer_unittest_deps = [ + nntrainer_dep, + gtest_dep + ] +endif + +if get_option('enable-capi') + subdir('tizen_capi') +endif diff --git a/test/tizen_capi/meson.build b/test/tizen_capi/meson.build new file mode 100644 index 0000000..4aacb00 --- /dev/null +++ b/test/tizen_capi/meson.build @@ -0,0 +1,14 @@ +unittest_tizen_deps = [ + nntrainer_capi_dep, + nntrainer_unittest_deps, + gtest_dep +] + +unittest_tizen_capi = executable('unittest_tizen_capi', + 'unittest_tizen_capi.cpp', + dependencies: [unittest_tizen_deps], + install: get_option('enable-test'), + install_dir: application_install_dir +) + +test('unittest_tizen_capi', unittest_tizen_capi) diff --git a/test/tizen_capi/unittest_tizen_capi.cpp b/test/tizen_capi/unittest_tizen_capi.cpp new file mode 100644 index 0000000..a096c68 --- /dev/null +++ b/test/tizen_capi/unittest_tizen_capi.cpp @@ -0,0 +1,60 @@ +/** + * 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. + */ +/** + * @file unittest_tizen_capi.cc + * @date 03 April 2020 + * @brief Unit test utility. + * @see https://github.com/nnstreamer/nntrainer + * @author Jijoong Moon + * @bug No known bugs + */ +#include +#include + +/** + * @brief Neural Network Model Contruct / Destruct Test (possitive test ) + * @return 0 success, -EADDRNOTAVIL if falied, -EFAULT if failed, -EVALID if failed. + */ +TEST(nntrainer_nnmodel_construct_deconstruct, nntrainer_01_p) { + ml_nnmodel_h handle; + int status; + status = ml_nnmodel_construct(&handle); + EXPECT_EQ(status, ML_ERROR_NONE); + status = ml_nnmodel_destruct(handle); + EXPECT_EQ(status, ML_ERROR_NONE); +} + +/** + * @brief Neural Network Model Destruct Test (negative test ) + * @return 0 success, -EINVAL if failed. + */ +TEST(nntrainer_nnmodel_construct_deconstruct, nntrainer_02_n) { + ml_nnmodel_h handle = NULL; + int status; + status = ml_nnmodel_destruct(handle); + EXPECT_EQ(status, ML_ERROR_INVALID_PARAMETER); +} + +/** + * @brief Main gtest + */ +int main(int argc, char **argv) { + int result = -1; + + testing::InitGoogleTest(&argc, argv); + + result = RUN_ALL_TESTS(); + + return result; +} -- 2.7.4