From b52d931d5529110f7c590cbf05ee87e3a2020070 Mon Sep 17 00:00:00 2001 From: Jihoon Lee Date: Wed, 18 Nov 2020 11:30:40 +0900 Subject: [PATCH] [Custom] Add an example scaffolding Add a layer example that depends on the user's custom code This patch generates scaffolding to the `Application/Custom` folder **Self evaluation:** 1. Build test: [X]Passed [ ]Failed [ ]Skipped 2. Run test: [X]Passed [ ]Failed [ ]Skipped Signed-off-by: Jihoon Lee --- Applications/Custom/LayerClient/README.md | 4 + Applications/Custom/LayerClient/jni/Android.mk | 70 ++++++++++++ Applications/Custom/LayerClient/jni/Application.mk | 3 + Applications/Custom/LayerClient/jni/main.cpp | 65 +++++++++++ Applications/Custom/LayerClient/jni/meson.build | 19 ++++ Applications/Custom/LayerClient/jni/pow.cpp | 13 +++ Applications/Custom/LayerClient/jni/pow.h | 119 +++++++++++++++++++++ .../Custom/LayerClient/res/custom_layer_client.ini | 20 ++++ Applications/Custom/README.md | 19 ++++ Applications/meson.build | 1 + 10 files changed, 333 insertions(+) create mode 100644 Applications/Custom/LayerClient/README.md create mode 100644 Applications/Custom/LayerClient/jni/Android.mk create mode 100644 Applications/Custom/LayerClient/jni/Application.mk create mode 100644 Applications/Custom/LayerClient/jni/main.cpp create mode 100644 Applications/Custom/LayerClient/jni/meson.build create mode 100644 Applications/Custom/LayerClient/jni/pow.cpp create mode 100644 Applications/Custom/LayerClient/jni/pow.h create mode 100644 Applications/Custom/LayerClient/res/custom_layer_client.ini create mode 100644 Applications/Custom/README.md diff --git a/Applications/Custom/LayerClient/README.md b/Applications/Custom/LayerClient/README.md new file mode 100644 index 0000000..555a1c2 --- /dev/null +++ b/Applications/Custom/LayerClient/README.md @@ -0,0 +1,4 @@ +# LayerClient Example + +This application demonstrates how to create a custom layer and register inside client-side code + diff --git a/Applications/Custom/LayerClient/jni/Android.mk b/Applications/Custom/LayerClient/jni/Android.mk new file mode 100644 index 0000000..5cd3da0 --- /dev/null +++ b/Applications/Custom/LayerClient/jni/Android.mk @@ -0,0 +1,70 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +# ndk path +ifndef ANDROID_NDK +$(error ANDROID_NDK is not defined!) +endif + +ifndef NNTRAINER_ROOT +NNTRAINER_ROOT := $(LOCAL_PATH)/../../../.. +endif + +NNTRAINER_INCLUDES := $(NNTRAINER_ROOT)/nntrainer \ + $(NNTRAINER_ROOT)/nntrainer/dataset \ + $(NNTRAINER_ROOT)/nntrainer/models \ + $(NNTRAINER_ROOT)/nntrainer/layers \ + $(NNTRAINER_ROOT)/nntrainer/optimizers \ + $(NNTRAINER_ROOT)/nntrainer/tensor \ + $(NNTRAINER_ROOT)/api \ + $(NNTRAINER_ROOT)/api/ccapi/include \ + $(NNTRAINER_ROOT)/api/capi/include/platform + +NNTRAINER_APPLICATION := $(NNTRAINER_ROOT)/Applications + +include $(CLEAR_VARS) + +LOCAL_MODULE := nntrainer +LOCAL_SRC_FILES := $(NNTRAINER_ROOT)/libs/$(TARGET_ARCH_ABI)/libnntrainer.so + +include $(PREBUILT_SHARED_LIBRARY) + +include $(CLEAR_VARS) + +LOCAL_MODULE := ccapi-nntrainer +LOCAL_SRC_FILES := $(NNTRAINER_ROOT)/libs/$(TARGET_ARCH_ABI)/libccapi-nntrainer.so + +include $(PREBUILT_SHARED_LIBRARY) + +include $(CLEAR_VARS) + +LOCAL_MODULE := app_utils +LOCAL_SRC_FILES := $(NNTRAINER_ROOT)/Applications/utils/libs/$(TARGET_ARCH_ABI)/libapp_utils.so +APP_UTILS_INCLUDES := $(NNTRAINER_ROOT)/Applications/utils/jni/includes + +include $(PREBUILT_SHARED_LIBRARY) + +include $(CLEAR_VARS) + +LOCAL_ARM_NEON := true +LOCAL_CFLAGS += -std=c++14 -Ofast -mcpu=cortex-a53 -Ilz4-nougat/lib +LOCAL_LDFLAGS += -Llz4-nougat/lib/obj/local/$(TARGET_ARCH_ABI)/ +LOCAL_CXXFLAGS += -std=c++14 +LOCAL_CFLAGS += -pthread -fexceptions +LOCAL_LDFLAGS += -fopenmp -fexceptions +LOCAL_MODULE_TAGS := optional +LOCAL_ARM_MODE := arm +LOCAL_MODULE := nntrainer_layer_client_example +LOCAL_LDLIBS := -llog + +LOCAL_SRC_FILES := main.cpp + +# todo: make this application only depending on ccapi +LOCAL_SHARED_LIBRARIES := nntrainer ccapi-nntrainer app_utils + +LOCAL_C_INCLUDES += $(NNTRAINER_INCLUDES) $(APP_UTILS_INCLUDES) + +include $(BUILD_EXECUTABLE) + + diff --git a/Applications/Custom/LayerClient/jni/Application.mk b/Applications/Custom/LayerClient/jni/Application.mk new file mode 100644 index 0000000..228f653 --- /dev/null +++ b/Applications/Custom/LayerClient/jni/Application.mk @@ -0,0 +1,3 @@ +APP_ABI = arm64-v8a +APP_STL = c++_shared +APP_PLATFORM=android-24 diff --git a/Applications/Custom/LayerClient/jni/main.cpp b/Applications/Custom/LayerClient/jni/main.cpp new file mode 100644 index 0000000..e0f57f5 --- /dev/null +++ b/Applications/Custom/LayerClient/jni/main.cpp @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: Apache-2.0 +/** + * Copyright (C) 2020 Jihoon Lee + * + * @file main.cpp + * @date 16 November 2020 + * @brief This file contains the execution part of LayerClient example + * @see https://github.com/nnstreamer/nntrainer + * @author Jihoon Lee + * @bug No known bugs except for NYI items + * + */ +#include +#include + +#include + +#include + +#define BATCH_SIZE 10 +#define FEATURE_SIZE 100 +#define NUM_CLASS 10 + +/** + * @brief get data which size is batch for train + * @param[out] outVec + * @param[out] outLabel + * @param[out] last if the data is finished + * @param[in] user_data private data for the callback + * @retval status for handling error + */ +int constant_generator_cb(float **outVec, float **outLabel, bool *last, + void *user_data) { + static int count = 0; + unsigned int i; + unsigned int data_size = BATCH_SIZE * FEATURE_SIZE; + + for (i = 0; i < data_size; ++i) { + outVec[0][i] = 1.0f; + } + + outLabel[0][0] = 1.0f; + for (i = 0; i < NUM_CLASS - 1; ++i) { + outLabel[0][i] = 0.0f; + } + + if (count == 10) { + *last = true; + count = 0; + } else { + *last = false; + count++; + } + + return ML_ERROR_NONE; +} + +int main(int argc, char *argv[]) { + /**< add argc */ + auto model = ml::train::createModel(ml::train::ModelType::NEURAL_NET); + + model->loadFromConfig("..model.ini"); + + std::cout << "This is an example scaffolding of LayerClient"; +} diff --git a/Applications/Custom/LayerClient/jni/meson.build b/Applications/Custom/LayerClient/jni/meson.build new file mode 100644 index 0000000..6add91f --- /dev/null +++ b/Applications/Custom/LayerClient/jni/meson.build @@ -0,0 +1,19 @@ +res_path = meson.current_source_dir() / '..' / 'res' + +layer_client_sources = [ + 'main.cpp' +] + +layer_client_inc = include_directories('.') + +ini_in_path = res_path / 'custom_layer_client.ini' +ini_out_path = meson.build_root() / 'custom_layer_client.ini' + +run_command('cp', ini_in_path, ini_out_path) + +e = executable('layer_client', + layer_client_sources, + dependencies: [app_utils_dep, iniparser_dep, nntrainer_dep, nntrainer_ccapi_dep], + install: get_option('install-app'), + install_dir: application_install_dir +) diff --git a/Applications/Custom/LayerClient/jni/pow.cpp b/Applications/Custom/LayerClient/jni/pow.cpp new file mode 100644 index 0000000..a985430 --- /dev/null +++ b/Applications/Custom/LayerClient/jni/pow.cpp @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: Apache-2.0 +/** + * Copyright (C) 2020 Jihoon Lee + * + * @file pow.cpp + * @date 16 November 2020 + * @brief This file contains the simple pow2 layer which squares input + * elements. + * @see https://github.com/nnstreamer/nntrainer + * @author Jihoon Lee + * @bug No known bugs except for NYI items + * + */ diff --git a/Applications/Custom/LayerClient/jni/pow.h b/Applications/Custom/LayerClient/jni/pow.h new file mode 100644 index 0000000..f2467b6 --- /dev/null +++ b/Applications/Custom/LayerClient/jni/pow.h @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: Apache-2.0 +/** + * Copyright (C) 2020 Jihoon Lee + * + * @file pow.h + * @date 16 November 2020 + * @brief This file contains the simple pow2 layer which squares input + * elements. + * @see https://github.com/nnstreamer/nntrainer + * @author Jihoon Lee + * @bug No known bugs except for NYI items + * + */ + +#ifndef __POW_LAYER_H__ +#define __POW_LAYER_H__ + +#include +#include + +namespace custom { +class PowLayer : public ml::train::Layer { +public: + /** + * @brief Construct a new Pow Layer object that does elementwise power + * + * @param exponent_ exponent + */ + PowLayer(float exponent_ = 1) : exponent(exponent_) {} + + /** + * @brief Destroy the Pow Layer object + * + */ + ~PowLayer(); + + /** + * @brief set Property of layer + * @param[in] values values of property + * @retval #ML_ERROR_NONE Successful. + * @retval #ML_ERROR_INVALID_PARAMETER invalid parameter. + */ + int setProperty(std::vector values) { + /**< NYI */ + return 1; + } + + /** + * @brief Set the Property by propertyType, this is not used in this demo + * + * @param type property type + * @param value value + */ + void setProperty(const ml::train::Layer::PropertyType type, + const std::string &value = "") { + /**< NOT USED */ + } + + /** + * @brief check if hyperparameter is valid + * + * @return int ML_ERROR_NONE if successful + */ + int checkValidataion() { return ML_ERROR_NONE; } + + /** + * @brief Get the Loss bound to the object + * + * @return float + */ + float getLoss() { return 0.0f; } + + /** + * @brief nntrainer forwarding function + * + * @param in input tensors + * @return nntrainer::sharedConstTensors output tensors + */ + nntrainer::sharedConstTensors forwarding(nntrainer::sharedConstTensors in) { + return in; + } + + /** + * @brief nntrainer backwaridng function + * + * @param in input tensors + * @param iteration number of iterations + * @return nntrainer::sharedConstTensors output tensors + */ + nntrainer::sharedConstTensors backwarding(nntrainer::sharedConstTensors in, + int iteration) { + return in; + } + + /** + * @brief initialize function + * + * @return int ML_ERROR_NONE if successful + */ + int initialize() { return 1; } + + /** + * @brief Get the Type object + * + * @return const std::string + */ + const std::string getType() const { return PowLayer::type; } + + static const std::string type; + +private: + float exponent; +}; + +const std::string PowLayer::type = "pow"; + +} // namespace custom + +#endif /* __POW_LAYER_H__ */ diff --git a/Applications/Custom/LayerClient/res/custom_layer_client.ini b/Applications/Custom/LayerClient/res/custom_layer_client.ini new file mode 100644 index 0000000..ad9ba43 --- /dev/null +++ b/Applications/Custom/LayerClient/res/custom_layer_client.ini @@ -0,0 +1,20 @@ +# This file will contain model.ini +# Network Section : Network +[Model] +Type = NeuralNetwork +Learning_rate = 0.001 +Epochs = 30000 +Optimizer = sgd +Loss = cross +batch_size = 10 + +# Layer Section : Name +[inputlayer] +Type = InputLayer +Input_Shape = 1:1:100 + +[outputlayer] +Type = fully_connected +unit = 10 +Bias_initializer = zeros +Activation = softmax diff --git a/Applications/Custom/README.md b/Applications/Custom/README.md new file mode 100644 index 0000000..e2c8330 --- /dev/null +++ b/Applications/Custom/README.md @@ -0,0 +1,19 @@ +# Application with Custom Object + +Applications inside this folder are dedicated to demonstrate how to create custom layers, optimizers or other supported objects. + +There are two ways to apply custom object to the code. + +1. Create an object as a part of client code and register it to NNTrainer on the client code. + Easy to write, less portable +2. Create an object as a dynamic library and NNTrainer load the dynamic library. + Portable, more configurations + + +## Structure of the folder + +`*Client` demonstrates how to generate an object inside a client code and register on the fly. +For example, `LayerClient` will demo about how to write a custom layer and register it. + +`*Plugin` demonstrates how to generate an object inside a plugin code and register on the fly. +For example, `OptimizerPlugin` will demo about how to create a custom optimizer as a pluggable library. diff --git a/Applications/meson.build b/Applications/meson.build index 103296b..947db73 100644 --- a/Applications/meson.build +++ b/Applications/meson.build @@ -8,3 +8,4 @@ subdir('VGG/jni') subdir('ReinforcementLearning/DeepQ/jni') subdir('TransferLearning/CIFAR_Classification/jni') subdir('TransferLearning/Draw_Classification/jni') +subdir('Custom/LayerClient/jni') -- 2.7.4