[Filter/Custom] Custom tensor postprocessing support
authorMyungJoo Ham <myungjoo.ham@samsung.com>
Fri, 1 Jun 2018 04:46:27 +0000 (13:46 +0900)
committer함명주/동작제어Lab(SR)/Principal Engineer/삼성전자 <myungjoo.ham@samsung.com>
Tue, 5 Jun 2018 08:12:04 +0000 (17:12 +0900)
NN developers may define their own custom tensor operations
in the format given byu tensor_common to let NNStreamer
do any custom operations on the tensor stream.

Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
CMakeLists.txt
include/tensor_common.h
include/tensor_typedef.h [new file with mode: 0644]
nnstreamer.pc.in [new file with mode: 0644]
packaging/nnstreamer.spec
tensor_filter/CMakeLists.txt
tensor_filter/README.md
tensor_filter/tensor_filter.c
tensor_filter/tensor_filter.h
tensor_filter/tensor_filter_custom.c [new file with mode: 0644]
tensor_filter/tensor_filter_custom.h [new file with mode: 0644]

index 51dcf4a..c13b2d4 100644 (file)
@@ -43,6 +43,12 @@ ELSE(TIZEN OR GTEST_LIB)
        SET(gtestInc /usr/src/gtest)
 ENDIF(TIZEN OR GTEST_LIB)
 
+IF (NOT INCLUDE_INSTALL_DIR)
+       # We need to define includedir path
+       SET (INCLUDE_INSTALL_DIR /usr/include)
+       MESSAGE ("Warning: INCLUDE_INSTALL_DIR not defined. Using /usr/include")
+ENDIF (NOT INCLUDE_INSTALL_DIR)
+
 pkg_check_modules(pkgs REQUIRED ${PKG_MODULES})
 
 INCLUDE_DIRECTORIES(
@@ -69,3 +75,12 @@ TARGET_LINK_LIBRARIES(unittest_common ${pkgs_LIBRARIES} ${gtestLink})
 
 ADD_SUBDIRECTORY(tensor_converter)
 ADD_SUBDIRECTORY(tensor_filter)
+
+CONFIGURE_FILE(nnstreamer.pc.in nnstreamer.pc @ONLY)
+
+INSTALL(FILES include/tensor_typedef.h
+       DESTINATION ${INCLUDE_INSTALL_DIR}/nnstreamer
+       )
+INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/nnstreamer.pc
+       DESTINATION ${LIB_INSTALL_DIR}/pkgconfig
+       )
index a2b8b84..06e06de 100644 (file)
 
 #include <glib.h>
 #include <stdint.h>
+#include "tensor_typedef.h"
 
 G_BEGIN_DECLS
 
-#define NNS_TENSOR_RANK_LIMIT  (4)
-/**
- * @brief Possible data element types of other/tensor.
- *
- * The current version supports NNS_UINT8 only as video-input.
- * There is no restrictions for inter-NN or sink-to-app.
- */
-typedef enum _nns_tensor_type {
-  _NNS_INT32 = 0,
-  _NNS_UINT32,
-  _NNS_INT16,
-  _NNS_UINT16,
-  _NNS_INT8,
-  _NNS_UINT8,
-  _NNS_FLOAT64,
-  _NNS_FLOAT32,
-
-  _NNS_END,
-} tensor_type;
-
 /**
  * @brief Possible input stream types for other/tensor.
  *
diff --git a/include/tensor_typedef.h b/include/tensor_typedef.h
new file mode 100644 (file)
index 0000000..9cd16df
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * NNStreamer Common Header, Typedef part, for export as devel package.
+ * Copyright (C) 2018 MyungJoo Ham <myungjoo.ham@samsung.com>
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
+ * which case the following provisions apply instead of the ones
+ * mentioned above:
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * @file       tensor_common_typedef.h
+ * @date       01 Jun 2018
+ * @brief      Common header file for NNStreamer, the GStreamer plugin for neural networks
+ * @see                http://github.com/TO-BE-DETERMINED-SOON
+ * @see                https://github.sec.samsung.net/STAR/nnstreamer
+ * @author     MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * To Packagers:
+ *
+ * This fils it to be packaged as "devel" package for NN developers.
+ */
+
+#ifndef __GST_TENSOR_TYPEDEF_H__
+#define __GST_TENSOR_TYPEDEF_H__
+
+#define NNS_TENSOR_RANK_LIMIT  (4)
+/**
+ * @brief Possible data element types of other/tensor.
+ *
+ * The current version supports NNS_UINT8 only as video-input.
+ * There is no restrictions for inter-NN or sink-to-app.
+ */
+typedef enum _nns_tensor_type {
+  _NNS_INT32 = 0,
+  _NNS_UINT32,
+  _NNS_INT16,
+  _NNS_UINT16,
+  _NNS_INT8,
+  _NNS_UINT8,
+  _NNS_FLOAT64,
+  _NNS_FLOAT32,
+
+  _NNS_END,
+} tensor_type;
+
+#endif /*__GST_TENSOR_TYPEDEF_H__*/
diff --git a/nnstreamer.pc.in b/nnstreamer.pc.in
new file mode 100644 (file)
index 0000000..75a2f16
--- /dev/null
@@ -0,0 +1,13 @@
+# Package Information for pkg-config
+
+prefix=@PREFIX@
+exec_prefix=@EXEC_PREFIX@
+libdir=@LIB_INSTALL_DIR@
+includedir=/usr/include/deviced
+
+Name: nnstreamer
+Description: Neural Network Suite for GStreamer
+Version: @VERSION@
+Requires:
+Libs:
+Cflags: -I${includedir}
index 63a6fcf..3e6cee1 100644 (file)
@@ -39,6 +39,13 @@ HTML pages of lcov results of NNStreamer generated during rpmbuild
 NNStreamer is a set of gstreamer plugins to support general neural networks
 and their plugins in a gstreamer stream.
 
+%package devel
+Summary:       Development package for custom tensor operator developers (tensor_filter/custom)
+Requires:      nnstreamer = %{version}-%{release}
+%description devel
+Development package for custom tensor operator developers (tensor_filter/custom).
+This contains corresponding header files and .pc pkgconfig file.
+
 %prep
 %setup -q
 cp %{SOURCE1001} .
@@ -102,7 +109,13 @@ cp -r result %{buildroot}%{_datadir}/nnstreamer/unittest/
 %defattr(-,root,root,-)
 # The libraries are in LGPLv2.1 (testcases and non GST-plugin components are APL2)
 %license LICENSE.LGPLv2.1
-%{_libdir}/*
+%{_libdir}/*.so
+%{_libdir}/*.so*
+# TODO generate .so files with version info. Migrate symbolic-link .so to devel.
+
+%files devel
+%{_includedir}/nnstreamer/*
+%{_libdir}/pkgconfig/nnstreamer.pc
 
 %if 0%{?testcoverage}
 %files unittest-coverage
index 6fb9ff6..1db2d76 100644 (file)
@@ -1,8 +1,12 @@
 CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
 
-ADD_LIBRARY(tensor_filter SHARED tensor_filter.c tensor_filter_tensorflow_lite.c)
+ADD_LIBRARY(tensor_filter SHARED
+       tensor_filter.c
+       tensor_filter_tensorflow_lite.c
+       tensor_filter_custom.c
+       )
 
-TARGET_LINK_LIBRARIES(tensor_filter ${pkgs_LIBRARIES})
+TARGET_LINK_LIBRARIES(tensor_filter dl ${pkgs_LIBRARIES})
 TARGET_INCLUDE_DIRECTORIES(tensor_filter PUBLIC ${pkgs_INCLUDE_DIRS})
 TARGET_COMPILE_OPTIONS(tensor_filter PUBLIC ${pkgs_CFLAGS_OTHER})
 
@@ -11,3 +15,6 @@ INSTALL(TARGETS tensor_filter
        LIBRARY DESTINATION ${LIB_INSTALL_DIR}
        ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
        )
+INSTALL(FILES tensor_filter_custom.h
+       DESTINATION ${INCLUDE_INSTALL_DIR}/nnstreamer
+       )
index ffee3be..c5cf42a 100644 (file)
@@ -22,7 +22,11 @@ This should fill in ```GstTensor_Filter_Framework``` supporting tensorflow_lite.
 
 ### Custom function support, ```tensor_filter_custom.c```
 
-This should fill in ```GstTensor_Filter_Framework``` supporting dlopen'ed custom shared objects, requiring such shared objects to provide its own defined functions.
+Neural network and streameline developers may define their own tensor postprocessing operations with tensor_filter_custom.
+
+With ```nnstreamer-devel``` package installed at build time (e.g., ```BuildRequires: pkgconfig(nnstreamer)``` in .spec file), develerops can implement their own functions and expose their functions via ```NNStreamer_custom_class``` defined in ```tensor_fitler_custom.h```. The resulting custom developer plugin should exist as a shared library (.so) with the symbol NNStreamer_custom exposed with all the func defined in NNStreamer_custom_class.
+
+@TODO Write an example custom filter for novice developers.
 
 ### We may add other NNFW as well (tensorflow, caffe, ...)
 
index c414a8a..ca4f15f 100644 (file)
@@ -85,7 +85,7 @@
 GstTensor_Filter_Framework *tensor_filter_supported[] = {
   [_T_F_UNDEFINED] = NULL,
 
-  [_T_F_CUSTOM] = NULL,
+  [_T_F_CUSTOM] = &NNS_support_custom,
   [_T_F_TENSORFLOW_LITE] = &NNS_support_tensorflow_lite,
   [_T_F_TENSORFLOW] = NULL,
   [_T_F_CAFFE2] = NULL,
@@ -285,6 +285,8 @@ gst_tensor_filter_init (GstTensor_Filter * filter)
   filter->outputDimension[2] = 1;
   filter->outputDimension[3] = 1; // out
   filter->outputType = _NNS_END; // not initialized
+
+  filter->privateData = NULL; // mark not initialized.
 }
 
 /**
index 2552dde..81e6dc2 100644 (file)
@@ -104,8 +104,8 @@ extern const char* nnfw_names[];
 static const gboolean nnfw_support_status[] = {
   FALSE,
 
-  FALSE,
-  FALSE,
+  TRUE,
+  TRUE,
   FALSE,
   FALSE,
 
@@ -162,9 +162,11 @@ struct _GstTensor_Filter_Framework
   int (*invoke_NN)(GstTensor_Filter *filter, void *inputptr, void *outputptr); /**< Mandatory callback. Invoke the given network model. */
   int (*getInputDimension)(GstTensor_Filter *filter, uint32_t *inputDimension, tensor_type *type); /**< Optional. Set NULL if not supported. Get dimension of input tensor */
   int (*getOutputDimension)(GstTensor_Filter *filter, uint32_t *outputDimension, tensor_type *type); /**< Optional. Set NULL if not supported. Get dimension of output tensor */
+  void (*close)(GstTensor_Filter *filter); /**< Optional. Close this instance! */
 };
 
 extern GstTensor_Filter_Framework NNS_support_tensorflow_lite;
+extern GstTensor_Filter_Framework NNS_support_custom;
 
 extern GstTensor_Filter_Framework *tensor_filter_supported[];
 
diff --git a/tensor_filter/tensor_filter_custom.c b/tensor_filter/tensor_filter_custom.c
new file mode 100644 (file)
index 0000000..8f6ba91
--- /dev/null
@@ -0,0 +1,182 @@
+/**
+ * GStreamer Tensor_Filter, Tensorflow-Lite Module
+ * Copyright (C) 2018 MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
+ * which case the following provisions apply instead of the ones
+ * mentioned above:
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * @file       tensor_filter_custom.c
+ * @date       01 Jun 2018
+ * @brief      Custom tensor post-processing interface for NNStreamer suite between NN developer-plugins and NNstreamer.
+ * @see                http://github.com/TO-BE-DETERMINED-SOON
+ * @see                https://github.sec.samsung.net/STAR/nnstreamer
+ * @author     MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * This is the per-NN-framework plugin (custom) for tensor_filter.
+ * Fill in "GstTensor_Filter_Framework" for tensor_filter.h/c
+ *
+ */
+
+#include "tensor_filter.h"
+#include "tensor_filter_custom.h"
+#include <glib.h>
+#include <dlfcn.h>
+
+struct _internal_data {
+  GstTensor_Filter *parent;
+
+  void *handle;
+  NNStreamer_custom_class *methods;
+
+  void* customFW_private_data;
+};
+typedef struct _internal_data internal_data;
+
+/**
+ * @brief Load the custom library. Will skip loading if it's already loaded.
+ * @return 0 if successfully loaded. 1 if skipped (already loaded). -1 if error
+ */
+static int custom_loadlib(GstTensor_Filter *filter) {
+  internal_data *ptr;
+  char *dlsym_error;
+
+  if (filter->privateData != NULL) {
+    /* @TODO : Check the integrity of filter->data and filter->modelFilename, nnfw */
+    return 1;
+  }
+
+  ptr = g_new0(internal_data, 0); /* Fill Zero! */
+  filter->privateData = ptr;
+  ptr->parent = filter;
+
+  /* Load .so if this is the first time for this instance. */
+  ptr->handle = dlopen(filter->modelFilename, RTLD_NOW);
+  if (!ptr->handle) {
+    g_free(ptr);
+    filter->privateData = NULL;
+    return -1;
+  }
+
+  dlerror();
+  ptr->methods = (NNStreamer_custom_class *) dlsym(ptr->handle, "NNStreamer_custom");
+  dlsym_error = dlerror();
+  if (dlsym_error) {
+    g_printerr("tensor_filter_custom:loadlib error: %s\n", dlsym_error);
+    dlclose(ptr->handle);
+    g_free(ptr);
+    filter->privateData = NULL;
+    return -1;
+  }
+
+  ptr->customFW_private_data = ptr->methods->initfunc();
+  return 0;
+}
+
+/**
+ * @brief The mandatory callback for GstTensor_Filter_Framework
+ * @param filter The parent object
+ * @param[in] inptr The input tensor
+ * @param[out] outptr The output tensor
+ */
+static int custom_invoke(GstTensor_Filter *filter, void *inptr, void *outptr) {
+  int retval = custom_loadlib(filter);
+  internal_data *ptr;
+
+  /* Actually, tensor_filter must have called getInput/OotputDim first. */
+  g_assert(retval != 0);
+
+  if (retval < 0)
+    return retval;
+
+  g_assert(filter->privateData);
+  ptr = filter->privateData;
+
+  return ptr->methods->invoke(ptr->customFW_private_data, inptr, outptr);
+}
+
+/**
+ * @brief The optional callback for GstTensor_Filter_Framework
+ */
+static int custom_getInputDim(GstTensor_Filter *filter, uint32_t *inputDimension, tensor_type *type) {
+  int retval = custom_loadlib(filter);
+  internal_data *ptr;
+
+  if (retval < 0)
+    return retval;
+
+  g_assert(filter->privateData);
+  ptr = filter->privateData;
+
+  return ptr->methods->getInputDim(ptr->customFW_private_data, inputDimension, type);
+}
+
+/**
+ * @brief The optional callback for GstTensor_Filter_Framework
+ */
+static int custom_getOutputDim(GstTensor_Filter *filter, uint32_t *outputDimension, tensor_type *type) {
+  int retval = custom_loadlib(filter);
+  internal_data *ptr;
+
+  if (retval < 0)
+    return retval;
+
+  g_assert(filter->privateData);
+  ptr = filter->privateData;
+
+  return ptr->methods->getOutputDim(ptr->customFW_private_data, outputDimension, type);
+}
+
+/**
+ * @brief Free privateData and move on.
+ */
+static void custom_close(GstTensor_Filter *filter) {
+  internal_data *ptr = filter->privateData;
+
+  ptr->methods->exitfunc(ptr->customFW_private_data);
+  g_free(ptr);
+  filter->privateData = NULL;
+}
+
+GstTensor_Filter_Framework NNS_support_custom = {
+  .name = "custom",
+  .allow_in_place = FALSE, // custom cannot support in-place (outptr == inptr).
+  .invoke_NN = custom_invoke,
+  .getInputDimension = custom_getInputDim,
+  .getOutputDimension = custom_getOutputDim,
+  .close = custom_close,
+};
diff --git a/tensor_filter/tensor_filter_custom.h b/tensor_filter/tensor_filter_custom.h
new file mode 100644 (file)
index 0000000..ee85c8d
--- /dev/null
@@ -0,0 +1,119 @@
+/**
+ * GStreamer Tensor_Filter, Tensorflow-Lite Module
+ * Copyright (C) 2018 MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * GNU Lesser General Public License Version 2.1 (the "LGPL"), in
+ * which case the following provisions apply instead of the ones
+ * mentioned above:
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * @file       tensor_filter_custom.h
+ * @date       01 Jun 2018
+ * @brief      Custom tensor post-processing interface for NNStreamer suite for post-processing code developers.
+ * @see                http://github.com/TO-BE-DETERMINED-SOON
+ * @see                https://github.sec.samsung.net/STAR/nnstreamer
+ * @author     MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * How To for NNdevelopers:
+ *
+ * 1. Define struct, "NNStreamer_custom", with the functions defined.
+ * 2. Compile as a shared object. (.so in Linux)
+ * 3. Use NNStreamer (tensor_filter framework=custom, model=FILEPATH_OF_YOUR_SO.so, ...)
+ *
+ * To Packagers:
+ *
+ * This file is to be packaged as "devel" package for NN developers.
+ */
+#ifndef __NNS_TENSOR_FILTER_CUSTOM_H__
+#define __NNS_TENSOR_FILTER_CUSTOM_H__
+
+#include <stdint.h>
+
+/**
+ * @brief A function that is called before calling other functions.
+ * @return The returned pointer will be passed to other functions as "private_data".
+ */
+typedef void *(*NNS_custom_init_func)(void);
+
+/**
+ * @brief A function that is called after calling other functions, when it's ready to close.
+ * @param[in] private_data If you have allocated *private_data at init, free it here.
+ */
+typedef void (*NNS_custom_exit_func)(void *private_data);
+
+/**
+ * @brief Get input tensor type.
+ * @param[in] private_data The pointer returned by NNStreamer_custom_exit.
+ * @param[out] inputDimension uint32_t[NNS_TENSOR_RANK_LIMIT]
+ * @param[out] type Type of each element in the input tensor
+ */
+typedef int (*NNS_custom_get_input_dimension)(void *private_data,
+    uint32_t *inputDimension, tensor_type *type);
+
+/**
+ * @brief Get output tensor type.
+ * @param[in] private_data The pointer returned by NNStreamer_custom_exit.
+ * @param[out] outputDimension uint32_t[NNS_TENSOR_RANK_LIMIT]
+ * @param[out] type Type of each element in the output tensor
+ */
+typedef int (*NNS_custom_get_output_dimension)(void *private_data,
+    uint32_t *outputDimension, tensor_type *type);
+
+/**
+ * @brief Invoke the "main function".
+ * @param[in] private_data The pointer returned by NNStreamer_custom_exit.
+ * @param[in] inputPtr pointer to input tensor, size = dim1 x dim2 x dim3 x dim4 x typesize, allocated by caller
+ * @param[in] inputPtr pointer to output tensor, size = dim1 x dim2 x dim3 x dim4 x typesize, allocated by caller
+ */
+typedef int (*NNS_custom_invoke)(void *private_data,
+    void *inputPtr, void *outputPtr);
+
+/**
+ * @brief Custom Filter Class
+ *
+ * Note that exery function pointer is MANDATORY!
+ */
+struct _NNStreamer_custom_class {
+  NNS_custom_init_func initfunc;
+  NNS_custom_exit_func exitfunc;
+  NNS_custom_get_input_dimension getInputDim;
+  NNS_custom_get_output_dimension getOutputDim;
+  NNS_custom_invoke invoke;
+};
+typedef struct _NNStreamer_custom_class NNStreamer_custom_class;
+extern NNStreamer_custom_class *NNStreamer_custom;
+
+#endif /*__NNS_TENSOR_FILTER_CUSTOM_H__*/