[Filter/Tensorflow] remove memcpy by getting conf
authorHyoung Joo Ahn <hello.ahn@samsung.com>
Mon, 18 Mar 2019 10:00:39 +0000 (19:00 +0900)
committerMyungJoo Ham <myungjoo.ham@samsung.com>
Thu, 21 Mar 2019 07:21:04 +0000 (16:21 +0900)
Through conf, we can avoid the unexpected errors at the specific environment by turning on/off the option(memory optimization).

Signed-off-by: Hyoung Joo Ahn <hello.ahn@samsung.com>
ext/nnstreamer/tensor_filter/tensor_filter_tensorflow.c
ext/nnstreamer/tensor_filter/tensor_filter_tensorflow_core.cc
ext/nnstreamer/tensor_filter/tensor_filter_tensorflow_core.h
packaging/nnstreamer.spec

index effa2ec..39d4750 100644 (file)
@@ -30,6 +30,7 @@
 #include "tensor_filter_tensorflow_core.h"
 #include <glib.h>
 #include <string.h>
+#include <nnstreamer_conf.h>
 
 /**
  * @brief internal data of tensorflow
@@ -77,8 +78,12 @@ tf_loadModelFile (const GstTensorFilterProperties * prop, void **private_data)
   tf = g_new0 (tf_data, 1); /** initialize tf Fill Zero! */
   *private_data = tf;
   tf->tf_private_data = tf_core_new (prop->model_file);
+
+  const gboolean tf_mem_optmz =
+      nnsconf_get_value_bool (NNSCONF_VAL_TF_MEM_OPTMZ);
+
   if (tf->tf_private_data) {
-    if (tf_core_init (tf->tf_private_data, prop)) {
+    if (tf_core_init (tf->tf_private_data, prop, tf_mem_optmz)) {
       g_printerr ("failed to initailize the object: tensorflow");
       return -2;
     }
index 1dd22e5..d697e93 100644 (file)
@@ -66,11 +66,14 @@ TFCore::~TFCore ()
  * @return 0 if OK. non-zero if error.
  */
 int
-TFCore::init (const GstTensorFilterProperties * prop)
+TFCore::init (const GstTensorFilterProperties * prop,
+  const gboolean tf_mem_optmz)
 {
   gst_tensors_info_copy (&inputTensorMeta, &prop->input_meta);
   gst_tensors_info_copy (&outputTensorMeta, &prop->output_meta);
 
+  mem_optmz = tf_mem_optmz;
+
   return loadModel ();
 }
 
@@ -183,6 +186,43 @@ TFCore::getTensorTypeFromTF (DataType tfType)
 }
 
 /**
+ * @brief      return the data type of the tensor for Tensorflow
+ * @param tType        : the defined type of NNStreamer
+ * @return the enum of defined tensorflow::DataType
+ */
+TF_DataType
+TFCore::getTensorTypeToTF_Capi (tensor_type tType)
+{
+  switch (tType) {
+    case _NNS_INT32:
+      return TF_INT32;
+    case _NNS_UINT32:
+      return TF_UINT32;
+    case _NNS_INT16:
+      return TF_INT16;
+    case _NNS_UINT16:
+      return TF_UINT16;
+    case _NNS_INT8:
+      return TF_INT8;
+    case _NNS_UINT8:
+      return TF_UINT8;
+    case _NNS_INT64:
+      return TF_INT64;
+    case _NNS_UINT64:
+      return TF_UINT64;
+    case _NNS_FLOAT32:
+      return TF_FLOAT;
+    case _NNS_FLOAT64:
+      return TF_DOUBLE;
+    default:
+      /** @todo Support other types */
+      break;
+  }
+  /* Since there is no INVALID, TF_RESOURCE is used to detect invalid datatype temporally */
+  return TF_RESOURCE;
+}
+
+/**
  * @brief      check the inserted information about input tensor with model
  * @return 0 if OK. non-zero if error.
  *        -1 if the number of input tensors is not matched.
@@ -363,6 +403,27 @@ TFCore::getOutputTensorDim (GstTensorsInfo * info)
 }
 
 /**
+ * @brief      ring cache structure
+ */
+class TFBuffer : public TensorBuffer {
+ public:
+  void* data_;
+  size_t len_;
+
+  void* data () const override { return data_; }
+  size_t size () const override { return len_; }
+  TensorBuffer* root_buffer () override { return this; }
+  void FillAllocationDescription (AllocationDescription* proto) const override {
+    int64 rb = size ();
+    proto->set_requested_bytes (rb);
+    proto->set_allocator_name (cpu_allocator ()->Name ());
+  }
+
+  // Prevents input forwarding from mutating this buffer.
+  bool OwnsMemory () const override { return false; }
+};
+
+/**
  * @brief      run the model with the input.
  * @param[in] input : The array of input tensors
  * @param[out]  output : The array of output tensors
@@ -379,16 +440,44 @@ TFCore::run (const GstTensorMemory * input, GstTensorMemory * output)
 
   std::vector <std::pair <string, Tensor>> input_feeds;
   std::vector <Tensor> outputs;
+  Tensor in;
 
   for (int i = 0; i < inputTensorMeta.num_tensors; ++i) {
-    Tensor in (input_tensor_info[i].type, input_tensor_info[i].shape);
-
-    /* copy data */
-    if (input_tensor_info[i].type == DT_STRING) {
-      in.scalar<string>()() = string ((char *) input[i].data, input[i].size);
-    } else {
-      std::copy_n ((char *) input[i].data, input[i].size,
-          const_cast<char *>(in.tensor_data().data()));
+
+    if (mem_optmz) {
+      TFBuffer *buf = new TFBuffer;
+      buf->len_ = input[i].size;
+      buf->data_ = input[i].data;
+
+      TF_DataType dataType = getTensorTypeToTF_Capi (input[i].type);
+
+      if (dataType == TF_RESOURCE){
+        g_critical ("This data type is not valid: %d", input[i].type);
+        buf->Unref();
+        return -1;
+      }
+
+      in = TensorCApi::MakeTensor (
+        dataType,
+        input_tensor_info[i].shape,
+        buf
+      );
+      if (!in.IsAligned ()) {
+        g_critical ("the input tensor %s is not aligned", inputTensorMeta.info[i].name);
+        buf->Unref();
+        return -2;
+      }
+    }
+    else {
+      in = Tensor (input_tensor_info[i].type, input_tensor_info[i].shape);
+
+      /* copy data */
+      if (input_tensor_info[i].type == DT_STRING) {
+        in.scalar<string>()() = string ((char *) input[i].data, input[i].size);
+      } else {
+        std::copy_n ((char *) input[i].data, input[i].size,
+            const_cast<char *>(in.tensor_data().data()));
+      }
     }
 
     input_feeds.push_back ({inputTensorMeta.info[i].name, in});
@@ -397,14 +486,19 @@ TFCore::run (const GstTensorMemory * input, GstTensorMemory * output)
   Status run_status =
       session->Run (input_feeds, output_tensor_names, {}, &outputs);
 
+  if (mem_optmz) {
+    TensorBuffer *buf = TensorCApi::Buffer (in);
+    buf->Unref();
+  }
+
   if (!run_status.ok()) {
-    GST_ERROR ("Failed to run model: %s\n", run_status.ToString().c_str());
+    g_critical ("Failed to run model: %s\n", run_status.ToString().c_str());
     return -1;
   }
 
   /* validate output tensor once */
   if (!configured && validateOutputTensor (outputs)) {
-    GST_ERROR ("Output Tensor Information is not valid");
+    g_critical ("Output Tensor Information is not valid");
     return -2;
   }
 
@@ -449,10 +543,11 @@ tf_core_delete (void * tf)
  * @return 0 if OK. non-zero if error.
  */
 int
-tf_core_init (void * tf, const GstTensorFilterProperties * prop)
+tf_core_init (void * tf, const GstTensorFilterProperties * prop,
+  const gboolean tf_mem_optmz)
 {
   TFCore *c = (TFCore *) tf;
-  return c->init (prop);
+  return c->init (prop, tf_mem_optmz);
 }
 
 /**
index 98de687..ce08017 100644 (file)
 #define TENSOR_FILTER_TENSORFLOW_CORE_H
 
 #include <tensor_typedef.h>
-
-#ifdef __cplusplus
 #include <glib.h>
 #include <gst/gst.h>
 #include <setjmp.h>
 #include <stdio.h>
 #include <string.h>
+
+#ifdef __cplusplus
 #include <iostream>
 #include <fstream>
 #include <algorithm>
 #include <vector>
 
+#include <tensorflow/c/c_api.h>
+#include <tensorflow/c/c_api_internal.h>
 #include <tensorflow/core/public/session.h>
 
 using namespace tensorflow;
@@ -64,7 +66,7 @@ public:
   TFCore (const char * _model_path);
    ~TFCore ();
 
-  int init(const GstTensorFilterProperties * prop);
+  int init (const GstTensorFilterProperties * prop, const gboolean tf_mem_optmz);
   int loadModel ();
   const char* getModelPath();
   int getInputTensorDim (GstTensorsInfo * info);
@@ -76,6 +78,7 @@ public:
 private:
 
   const char *model_path;
+  gboolean mem_optmz;
 
   GstTensorsInfo inputTensorMeta;  /**< The tensor info of input tensors */
   GstTensorsInfo outputTensorMeta;  /**< The tensor info of output tensors */
@@ -87,6 +90,7 @@ private:
   Session *session;
 
   tensor_type getTensorTypeFromTF (DataType tfType);
+  TF_DataType getTensorTypeToTF_Capi (tensor_type tType);
   int validateInputTensor (const GraphDef &graph_def);
   int validateOutputTensor (const std::vector <Tensor> &outputs);
 };
@@ -100,7 +104,8 @@ extern "C"
 
   void *tf_core_new (const char *_model_path);
   void tf_core_delete (void * tf);
-  int tf_core_init (void * tf, const GstTensorFilterProperties * prop);
+  int tf_core_init (void * tf, const GstTensorFilterProperties * prop,
+      const gboolean tf_mem_optmz);
   const char *tf_core_getModelPath (void * tf);
   int tf_core_getInputDim (void * tf, GstTensorsInfo * info);
   int tf_core_getOutputDim (void * tf, GstTensorsInfo * info);
index d045a29..614911a 100644 (file)
@@ -172,6 +172,7 @@ ninja -C build %{?_smp_mflags}
     export NNSTREAMER_DECODERS=$(pwd)/ext/nnstreamer/tensor_decoder
     %ifarch x86_64 aarch64
     export TEST_TENSORFLOW=1
+    export NNSTREAMER_TF_MEM_OPTMZ=0
     %endif
     ./tests/unittest_common
     ./tests/unittest_sink --gst-plugin-path=.