From 3ccd4ec076334248be72ff3ac6393e4503c59111 Mon Sep 17 00:00:00 2001 From: Hyoung Joo Ahn Date: Mon, 18 Mar 2019 19:00:39 +0900 Subject: [PATCH] [Filter/Tensorflow] remove memcpy by getting conf 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 --- .../tensor_filter/tensor_filter_tensorflow.c | 7 +- .../tensor_filter/tensor_filter_tensorflow_core.cc | 121 ++++++++++++++++++--- .../tensor_filter/tensor_filter_tensorflow_core.h | 13 ++- packaging/nnstreamer.spec | 1 + 4 files changed, 124 insertions(+), 18 deletions(-) diff --git a/ext/nnstreamer/tensor_filter/tensor_filter_tensorflow.c b/ext/nnstreamer/tensor_filter/tensor_filter_tensorflow.c index effa2ec..39d4750 100644 --- a/ext/nnstreamer/tensor_filter/tensor_filter_tensorflow.c +++ b/ext/nnstreamer/tensor_filter/tensor_filter_tensorflow.c @@ -30,6 +30,7 @@ #include "tensor_filter_tensorflow_core.h" #include #include +#include /** * @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; } diff --git a/ext/nnstreamer/tensor_filter/tensor_filter_tensorflow_core.cc b/ext/nnstreamer/tensor_filter/tensor_filter_tensorflow_core.cc index 1dd22e5..d697e93 100644 --- a/ext/nnstreamer/tensor_filter/tensor_filter_tensorflow_core.cc +++ b/ext/nnstreamer/tensor_filter/tensor_filter_tensorflow_core.cc @@ -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 > input_feeds; std::vector 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 ((char *) input[i].data, input[i].size); - } else { - std::copy_n ((char *) input[i].data, input[i].size, - const_cast(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 ((char *) input[i].data, input[i].size); + } else { + std::copy_n ((char *) input[i].data, input[i].size, + const_cast(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); } /** diff --git a/ext/nnstreamer/tensor_filter/tensor_filter_tensorflow_core.h b/ext/nnstreamer/tensor_filter/tensor_filter_tensorflow_core.h index 98de687..ce08017 100644 --- a/ext/nnstreamer/tensor_filter/tensor_filter_tensorflow_core.h +++ b/ext/nnstreamer/tensor_filter/tensor_filter_tensorflow_core.h @@ -27,18 +27,20 @@ #define TENSOR_FILTER_TENSORFLOW_CORE_H #include - -#ifdef __cplusplus #include #include #include #include #include + +#ifdef __cplusplus #include #include #include #include +#include +#include #include 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 &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); diff --git a/packaging/nnstreamer.spec b/packaging/nnstreamer.spec index d045a29..614911a 100644 --- a/packaging/nnstreamer.spec +++ b/packaging/nnstreamer.spec @@ -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=. -- 2.7.4