[Example] Custom filter, "dummy LSTM", added
authorMyungJoo Ham <myungjoo.ham@samsung.com>
Fri, 2 Nov 2018 09:32:08 +0000 (18:32 +0900)
committerJijoong Moon <jijoong.moon@samsung.com>
Tue, 6 Nov 2018 01:09:01 +0000 (10:09 +0900)
This custom example filer, "dummy LSTM", is for recurrent
neural network test, mentioned in #738, as the second item.

Note that the third item (pipeline with valid recurrences)
requires new features in tensor_mux.

Signed-off-by: MyungJoo Ham <myungjoo.ham@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 affe3d5..793ac8f 100644 (file)
@@ -13,6 +13,7 @@ ADD_SUBDIRECTORY(custom_example_passthrough)
 ADD_SUBDIRECTORY(custom_example_scaler)
 ADD_SUBDIRECTORY(custom_example_average)
 ADD_SUBDIRECTORY(custom_example_opencv)
+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..8f804da
--- /dev/null
@@ -0,0 +1,9 @@
+ADD_LIBRARY(dummyLSTM SHARED dummy_LSTM.c)
+
+TARGET_LINK_LIBRARIES(dummyLSTM nnstreamer)
+
+INSTALL(TARGETS dummyLSTM
+       RUNTIME DESTINATION ${EXEC_PREFIX}
+       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..469b0e2
--- /dev/null
@@ -0,0 +1,160 @@
+/**
+ * NNStreamer Custom Filter LSTM Example, "dummyLSTM"
+ * Copyright (C) 2018 MyungJoo Ham <myungjoo.ham@samsung.com>
+ *
+ * LICENSE: LGPL-2.1
+ *
+ * @file       dummy_LSTM.c
+ * @date       02 Nov 2018
+ * @brief      Custom NNStreamer LSTM Model. "Dummy LSTM"
+ * @author     MyungJoo Ham <myungjoo.ham@samsung.com>
+ * @bug                No known bugs except for NYI items
+ *
+ * This supports two "4:4:4:1" uint8 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 <tensor_filter_custom.h>
+/* To use nnstreamer utilities (not mandatory for custom filters */
+#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[2]; /**< tensor info. 0:new frame / 1: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_UINT8;
+  data->info[1] = 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 uint8, 4:4:4 uint8)
+ */
+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 = 2;
+  info->info[0] = data->info[0];
+  info->info[1] = data->info[1];
+  return 0;
+}
+
+/**
+ * @brief get the output tensor dimensions of dummy-LSTM (4:4:4 uint8)
+ */
+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 = 1;
+  info->info[0] = data->info[0];
+  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;
+  uint8_t *in0, *in1, *out;
+
+  if (!data || !input || !output)
+    return -EINVAL;
+
+  in0 = input[0].data;
+  in1 = input[1].data;
+  out = output[0].data;
+
+  if (!in0 || !in1 || !out)
+    return -EINVAL;
+
+  for (h = 0; h < 4; h++) {
+    w = 0;
+    memcpy (&(out[location (0, w, h)]), &(in0[location (0, w, h)]), TSIZE);
+    for (w = 1; w <= 2; w++) {
+      for (c = 0; c < TSIZE; c++) {
+        uint16_t sum = in0[location (0, w, h)];
+        sum += in1[location (0, w, h)];
+        out[location (0, w, h)] = sum / 2;
+      }
+    }
+    w = 3;
+    memcpy (&(out[location (0, w, h)]), &(in1[location (0, w, h)]), TSIZE);
+  }
+  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;