[DummyLSTM] Add Dummy LSTM custom example
authorjijoong.moon <jijoong.moon@samsung.com>
Wed, 28 Nov 2018 02:33:42 +0000 (11:33 +0900)
committerMyungJoo Ham <myungjoo.ham@gmail.com>
Thu, 29 Nov 2018 07:57:43 +0000 (07:57 +0000)
Add Dymmy LSTM custom example. Two input stream and two outputstream.
First input is recursion and Second input is new input stream. First
output is recursion stream which is matched with first inputstream and
the second output stream is matched with second input stream.

 - in2_tmp0 = (in2+in1)/2 (in2_tmp0 : mimic sigmoid)
 - in2_tmp1 = tanh(in2)
 - in0 = in0 x in2_tmp0
 - in0 = in0 + (in2_tmp0 x in2_tmp1)
 - out0 = in0
 - out1 = in1 = (tanh(in0) x in2_tmp0)

                     +------------+
         in0 ------->|            |----> out0
         in1 ------->| dummy LSTM |----> out1
         in2 (new)-->|            |  |
                     +------------+  +--> out (equal out1)

**Self evaluation:**
1. Build test:  [X]Passed [ ]Failed [ ]Skipped
2. Run test:  [X]Passed [ ]Failed [ ]Skipped

Signed-off-by: jijoong.moon <jijoong.moon@samsung.com>
nnstreamer_example/CMakeLists.txt
nnstreamer_example/custom_example_LSTM/CMakeLists.txt [new file with mode: 0644]
nnstreamer_example/custom_example_LSTM/dummy_LSTM.c [new file with mode: 0644]

index fdd9f0b..d0868d5 100644 (file)
@@ -15,6 +15,7 @@ ADD_SUBDIRECTORY(custom_example_scaler)
 ADD_SUBDIRECTORY(custom_example_average)
 ADD_SUBDIRECTORY(custom_example_opencv)
 ADD_SUBDIRECTORY(custom_example_RNN)
+ADD_SUBDIRECTORY(custom_example_LSTM)
 ADD_SUBDIRECTORY(example_cam)
 ADD_SUBDIRECTORY(example_sink)
 ADD_SUBDIRECTORY(example_filter)
diff --git a/nnstreamer_example/custom_example_LSTM/CMakeLists.txt b/nnstreamer_example/custom_example_LSTM/CMakeLists.txt
new file mode 100644 (file)
index 0000000..9ba8391
--- /dev/null
@@ -0,0 +1,8 @@
+ADD_LIBRARY(dummyLSTM SHARED dummy_LSTM.c)
+
+TARGET_LINK_LIBRARIES(dummyLSTM nnstreamer)
+
+INSTALL(TARGETS dummyLSTM
+       LIBRARY DESTINATION ${LIB_INSTALL_DIR}
+       ARCHIVE DESTINATION ${LIB_INSTALL_DIR}
+       )
diff --git a/nnstreamer_example/custom_example_LSTM/dummy_LSTM.c b/nnstreamer_example/custom_example_LSTM/dummy_LSTM.c
new file mode 100644 (file)
index 0000000..79b0840
--- /dev/null
@@ -0,0 +1,166 @@
+/**
+ * NNStreamer Custom Filter LSTM Example, "dummyLSTM"
+ * Copyright (C) 2018 Jijoong Moon <jijoong.moon@samsung.com>
+ *
+ * LICENSE: LGPL-2.1
+ *
+ * @file       dummy_LSTM.c
+ * @date       28 Nov 2018
+ * @brief      Custom NNStreamer LSTM Model. "Dummy LSTM"
+ * @author     Jijoong Moon <jijoong.moon@samsung.com>
+ * @bug                No known bugs except for NYI items
+ *
+ * This supports two "4:4:4:1" float32 tensors, where the first one is the new tensor and the second one is "recurring" tensor (output of the previous frame).
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <math.h>
+#include <tensor_filter_custom.h>
+#include <tensor_common.h>
+
+#define TSIZE   (4)
+
+/**
+ * @brief _pt_data
+ */
+typedef struct _pt_data
+{
+  uint32_t id; /***< Just for testing */
+  uint32_t counter; /**< Internal frame counter for debugging/demo */
+  GstTensorInfo info[3]; /**< tensor info. 0:new frame / 1:recurring frame 2:recurring frame*/
+} pt_data;
+
+/**
+ * @brief Initialize dummy-LSTM
+ */
+static void *
+pt_init (const GstTensorFilterProperties * prop)
+{
+  pt_data *data = (pt_data *) malloc (sizeof (pt_data));
+  int i;
+
+  data->id = 0;
+  data->counter = 0;
+  data->info[0].dimension[0] = TSIZE;
+  data->info[0].dimension[1] = TSIZE;
+  data->info[0].dimension[2] = TSIZE;
+  for (i = 3; i < NNS_TENSOR_RANK_LIMIT; i++)
+    data->info[0].dimension[i] = 1;
+  data->info[0].type = _NNS_FLOAT32;
+  data->info[1] = data->info[0];
+  data->info[2] = data->info[0];
+
+  return data;
+}
+
+/**
+ * @brief Exit dummy-LSTM
+ */
+static void
+pt_exit (void *private_data, const GstTensorFilterProperties * prop)
+{
+  pt_data *data = private_data;
+  assert (data);
+  free (data);
+}
+
+/**
+ * @brief get the input tensor dimensions of dummy-LSTM (4:4:4 float32, 4:4:4 float32)
+ */
+static int
+get_inputDim (void *private_data, const GstTensorFilterProperties * prop,
+    GstTensorsInfo * info)
+{
+  pt_data *data = private_data;
+
+  assert (data);
+  assert (NNS_TENSOR_RANK_LIMIT >= 3);
+
+  info->num_tensors = 3;
+  info->info[0] = data->info[0];
+  info->info[1] = data->info[1];
+  info->info[2] = data->info[2];
+  return 0;
+}
+
+/**
+ * @brief get the output tensor dimensions of dummy-LSTM (4:4:4 float32)
+ */
+static int
+get_outputDim (void *private_data, const GstTensorFilterProperties * prop,
+    GstTensorsInfo * info)
+{
+  pt_data *data = private_data;
+
+  assert (data);
+  assert (NNS_TENSOR_RANK_LIMIT >= 3);
+
+  info->num_tensors = 2;
+  info->info[0] = data->info[0];
+  info->info[1] = data->info[1];
+  return 0;
+}
+
+/**
+ * @brief Get the offset of the tensor data blob pointer.
+ */
+static size_t
+location (uint32_t c, uint32_t w, uint32_t h)
+{
+  return c + TSIZE * (w + TSIZE * h);
+}
+
+/**
+ * @brief INFERENCE!
+ */
+static int
+pt_invoke (void *private_data, const GstTensorFilterProperties * prop,
+    const GstTensorMemory * input, GstTensorMemory * output)
+{
+  pt_data *data = private_data;
+  uint32_t c, w, h;
+  float *in0, *in1, *in2, *out0, *out1;
+  float in2_tmp0, in2_tmp1;
+
+  if (!data || !input || !output)
+    return -EINVAL;
+
+  in0 = input[0].data;
+  in1 = input[1].data;
+  in2 = input[2].data;
+  out0 = output[0].data;
+  out1 = output[1].data;
+
+  if (!in0 || !in1 || !in2 || !out0 || !out1)
+    return -EINVAL;
+
+  for (h = 0; h < TSIZE; h++) {
+    for (w = 0; w < TSIZE; w++) {
+      for (c = 0; c < TSIZE; c++) {
+        in2_tmp0 = (in2[location (c, w, h)] + in1[location (c, w, h)]) / 2;
+        in2_tmp1 = tanh (in2[location (c, w, h)]);
+        in0[location (c, w, h)] = in0[location (c, w, h)] * in2_tmp0;
+        in0[location (c, w, h)] += (in2_tmp0 * in2_tmp1);
+        out0[location (c, w, h)] = in0[location (c, w, h)];
+        out1[location (c, w, h)] = tanh (in0[location (c, w, h)]) * in2_tmp0;
+      }
+    }
+  }
+
+  return 0;
+}
+
+static NNStreamer_custom_class NNStreamer_custom_body = {
+  .initfunc = pt_init,
+  .exitfunc = pt_exit,
+  .getInputDim = get_inputDim,
+  .getOutputDim = get_outputDim,
+  .invoke = pt_invoke,
+};
+
+/* The dyn-loaded object */
+NNStreamer_custom_class *NNStreamer_custom = &NNStreamer_custom_body;