--- /dev/null
+# LayerClient Example
+
+This application demonstrates how to create a custom layer and register inside client-side code
+
--- /dev/null
+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)
+
+
--- /dev/null
+APP_ABI = arm64-v8a
+APP_STL = c++_shared
+APP_PLATFORM=android-24
--- /dev/null
+// SPDX-License-Identifier: Apache-2.0
+/**
+ * Copyright (C) 2020 Jihoon Lee <jhoon.it.lee@samsung.com>
+ *
+ * @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 <jhoon.it.lee@samsung.com>
+ * @bug No known bugs except for NYI items
+ *
+ */
+#include <iostream>
+#include <memory>
+
+#include <model.h>
+
+#include <pow.h>
+
+#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";
+}
--- /dev/null
+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
+)
--- /dev/null
+// SPDX-License-Identifier: Apache-2.0
+/**
+ * Copyright (C) 2020 Jihoon Lee <jhoon.it.lee@samsung.com>
+ *
+ * @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 <jhoon.it.lee@samsung.com>
+ * @bug No known bugs except for NYI items
+ *
+ */
--- /dev/null
+// SPDX-License-Identifier: Apache-2.0
+/**
+ * Copyright (C) 2020 Jihoon Lee <jhoon.it.lee@samsung.com>
+ *
+ * @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 <jhoon.it.lee@samsung.com>
+ * @bug No known bugs except for NYI items
+ *
+ */
+
+#ifndef __POW_LAYER_H__
+#define __POW_LAYER_H__
+
+#include <layer.h>
+#include <tensor.h>
+
+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<std::string> 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__ */
--- /dev/null
+# 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
--- /dev/null
+# 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.
subdir('ReinforcementLearning/DeepQ/jni')
subdir('TransferLearning/CIFAR_Classification/jni')
subdir('TransferLearning/Draw_Classification/jni')
+subdir('Custom/LayerClient/jni')