[C-Api/Single] check invalid tensor info
authorJaeyun <jy1210.jung@samsung.com>
Wed, 4 Dec 2019 04:16:03 +0000 (13:16 +0900)
committerMyungJoo Ham <myungjoo.ham@samsung.com>
Wed, 11 Dec 2019 02:09:27 +0000 (11:09 +0900)
Check input/output tensor info when opening the nn model.
If given info is not matched with model, try to change input info for dynamic mode.

Signed-off-by: Jaeyun Jung <jy1210.jung@samsung.com>
api/capi/src/nnstreamer-capi-single.c
tests/tizen_capi/unittest_tizen_capi.cpp

index 468d89a..0066771 100644 (file)
@@ -322,9 +322,10 @@ ml_single_set_info_in_handle (ml_single_h single, gboolean is_input,
     ml_tensors_info_s * tensors_info)
 {
   ml_single *single_h;
+  ml_tensors_info_h info = NULL;
   ml_tensors_info_s *dest;
-  bool valid = false;
-  gboolean configured = false;
+  gboolean configured = FALSE;
+  gboolean is_valid = FALSE;
   GTensorFilterSingleClass *klass;
   GObject * filter_obj;
 
@@ -343,24 +344,33 @@ ml_single_set_info_in_handle (ml_single_h single, gboolean is_input,
     configured = klass->output_configured (single_h->filter);
   }
 
-  if (tensors_info) {
-    if (!configured)
-      ml_single_set_inout_tensors_info (filter_obj, is_input, tensors_info);
-    ml_tensors_info_clone (dest, tensors_info);
-  } else {
-    ml_tensors_info_h info;
-
+  if (configured) {
+    /* get configured info and compare with input info */
     ml_single_get_tensors_info_from_filter (single_h->filter, is_input, &info);
+
+    if (tensors_info && !ml_tensors_info_is_equal (tensors_info, info)) {
+      /* given input info is not matched with configured */
+      if (is_input) {
+        /* try to update tensors info */
+        ml_tensors_info_destroy (info);
+        if (ml_single_update_info (single, tensors_info, &info) != ML_ERROR_NONE)
+          goto done;
+      } else {
+        goto done;
+      }
+    }
+
     ml_tensors_info_clone (dest, info);
-    ml_tensors_info_destroy (info);
+  } else if (tensors_info) {
+    ml_single_set_inout_tensors_info (filter_obj, is_input, tensors_info);
+    ml_tensors_info_clone (dest, tensors_info);
   }
 
-  if (!ml_tensors_info_is_valid (dest, valid)) {
-    /* invalid tensors info */
-    return FALSE;
-  }
+  is_valid = ml_tensors_info_is_valid (dest);
 
-  return TRUE;
+done:
+  ml_tensors_info_destroy (info);
+  return is_valid;
 }
 
 /**
@@ -377,7 +387,6 @@ ml_single_open (ml_single_h * single, const char *model,
   GTensorFilterSingleClass *klass;
   ml_tensors_info_s *in_tensors_info, *out_tensors_info;
   bool available = false;
-  bool valid = false;
   GError * error;
 
   check_feature_state ();
@@ -395,13 +404,13 @@ ml_single_open (ml_single_h * single, const char *model,
   out_tensors_info = (ml_tensors_info_s *) output_info;
 
   /* Validate input tensor info. */
-  if (input_info && !ml_tensors_info_is_valid (input_info, valid)) {
+  if (input_info && !ml_tensors_info_is_valid (input_info)) {
     ml_loge ("The given param, input tensor info is invalid.");
     return ML_ERROR_INVALID_PARAMETER;
   }
 
   /* Validate output tensor info. */
-  if (output_info && !ml_tensors_info_is_valid (output_info, valid)) {
+  if (output_info && !ml_tensors_info_is_valid (output_info)) {
     ml_loge ("The given param, output tensor info is invalid.");
     return ML_ERROR_INVALID_PARAMETER;
   }
@@ -755,14 +764,13 @@ ml_single_set_input_info (ml_single_h single, const ml_tensors_info_h info)
   int status = ML_ERROR_NONE;
   ml_tensors_info_s *in_info;
   GstTensorsInfo gst_in_info, gst_out_info;
-  bool valid = false;
 
   check_feature_state ();
 
   if (!single || !info)
     return ML_ERROR_INVALID_PARAMETER;
 
-  if (!ml_tensors_info_is_valid (info, valid))
+  if (!ml_tensors_info_is_valid (info))
     return ML_ERROR_INVALID_PARAMETER;
 
   ML_SINGLE_GET_VALID_HANDLE_LOCKED (single_h, single, 0);
index 2086239..63539fb 100644 (file)
@@ -2011,11 +2011,9 @@ TEST (nnstreamer_capi_singleshot, unavailable_fw_tf_n)
  * @brief Test NNStreamer single shot (tensorflow-lite)
  * @detail Failure case with invalid param.
  */
-TEST (nnstreamer_capi_singleshot, failure_01_n)
+TEST (nnstreamer_capi_singleshot, open_fail_01_n)
 {
   ml_single_h single;
-  ml_tensors_info_h in_info, out_info;
-  ml_tensor_dimension in_dim, out_dim;
   int status;
 
   const gchar *root_path = g_getenv ("NNSTREAMER_BUILD_ROOT_PATH");
@@ -2029,43 +2027,101 @@ TEST (nnstreamer_capi_singleshot, failure_01_n)
       "mobilenet_v1_1.0_224_quant.tflite", NULL);
   ASSERT_TRUE (g_file_test (test_model, G_FILE_TEST_EXISTS));
 
-  ml_tensors_info_create (&in_info);
-  ml_tensors_info_create (&out_info);
-
   /* invalid file path */
-  status = ml_single_open (&single, "wrong_file_name", in_info, out_info,
+  status = ml_single_open (&single, "wrong_file_name", NULL, NULL,
       ML_NNFW_TYPE_TENSORFLOW_LITE, ML_NNFW_HW_ANY);
   EXPECT_EQ (status, ML_ERROR_INVALID_PARAMETER);
 
   /* null file path */
-  status = ml_single_open (&single, NULL, in_info, out_info,
+  status = ml_single_open (&single, NULL, NULL, NULL,
       ML_NNFW_TYPE_TENSORFLOW_LITE, ML_NNFW_HW_ANY);
   EXPECT_EQ (status, ML_ERROR_INVALID_PARAMETER);
 
   /* invalid handle */
-  status = ml_single_open (NULL, test_model, in_info, out_info,
+  status = ml_single_open (NULL, test_model, NULL, NULL,
       ML_NNFW_TYPE_TENSORFLOW_LITE, ML_NNFW_HW_ANY);
   EXPECT_EQ (status, ML_ERROR_INVALID_PARAMETER);
 
+  /* invalid file extension */
+  status = ml_single_open (&single, test_model, NULL, NULL,
+      ML_NNFW_TYPE_TENSORFLOW, ML_NNFW_HW_ANY);
+  EXPECT_EQ (status, ML_ERROR_INVALID_PARAMETER);
+
+  /* invalid handle */
+  status = ml_single_close (single);
+  EXPECT_EQ (status, ML_ERROR_INVALID_PARAMETER);
+
+  /* Successfully opened unknown fw type (tf-lite) */
+  status = ml_single_open (&single, test_model, NULL, NULL,
+      ML_NNFW_TYPE_ANY, ML_NNFW_HW_ANY);
+  EXPECT_EQ (status, ML_ERROR_NONE);
+
+  status = ml_single_close (single);
+  EXPECT_EQ (status, ML_ERROR_NONE);
+
+  g_free (test_model);
+}
+
+/**
+ * @brief Test NNStreamer single shot (tensorflow-lite)
+ * @detail Failure case with invalid tensor info.
+ */
+TEST (nnstreamer_capi_singleshot, open_fail_02_n)
+{
+  ml_single_h single;
+  ml_tensors_info_h in_info, out_info;
+  ml_tensor_dimension in_dim, out_dim;
+  int status;
+
+  const gchar *root_path = g_getenv ("NNSTREAMER_BUILD_ROOT_PATH");
+  gchar *test_model;
+
+  /* supposed to run test in build directory */
+  if (root_path == NULL)
+    root_path = "..";
+
+  test_model = g_build_filename (root_path, "tests", "test_models", "models",
+      "mobilenet_v1_1.0_224_quant.tflite", NULL);
+  ASSERT_TRUE (g_file_test (test_model, G_FILE_TEST_EXISTS));
+
+  ml_tensors_info_create (&in_info);
+  ml_tensors_info_create (&out_info);
+
   /* invalid input tensor info */
-  status = ml_single_open (&single, test_model, in_info, out_info,
+  status = ml_single_open (&single, test_model, in_info, NULL,
+      ML_NNFW_TYPE_TENSORFLOW_LITE, ML_NNFW_HW_ANY);
+  EXPECT_EQ (status, ML_ERROR_INVALID_PARAMETER);
+
+  /* invalid output tensor info */
+  status = ml_single_open (&single, test_model, NULL, out_info,
       ML_NNFW_TYPE_TENSORFLOW_LITE, ML_NNFW_HW_ANY);
   EXPECT_EQ (status, ML_ERROR_INVALID_PARAMETER);
 
   in_dim[0] = 3;
-  in_dim[1] = 224;
-  in_dim[2] = 224;
+  in_dim[1] = 100;
+  in_dim[2] = 100;
   in_dim[3] = 1;
   ml_tensors_info_set_count (in_info, 1);
   ml_tensors_info_set_tensor_type (in_info, 0, ML_TENSOR_TYPE_UINT8);
   ml_tensors_info_set_tensor_dimension (in_info, 0, in_dim);
 
-  /* invalid output tensor info */
-  status = ml_single_open (&single, test_model, in_info, out_info,
+  /* invalid input dimension (model does not support dynamic dimension) */
+  status = ml_single_open (&single, test_model, in_info, NULL,
       ML_NNFW_TYPE_TENSORFLOW_LITE, ML_NNFW_HW_ANY);
   EXPECT_EQ (status, ML_ERROR_INVALID_PARAMETER);
 
-  out_dim[0] = 1001;
+  in_dim[1] = in_dim[2] = 224;
+  ml_tensors_info_set_tensor_dimension (in_info, 0, in_dim);
+  ml_tensors_info_set_tensor_type (in_info, 0, ML_TENSOR_TYPE_UINT16);
+
+  /* invalid input type */
+  status = ml_single_open (&single, test_model, in_info, NULL,
+      ML_NNFW_TYPE_TENSORFLOW_LITE, ML_NNFW_HW_ANY);
+  EXPECT_EQ (status, ML_ERROR_INVALID_PARAMETER);
+
+  ml_tensors_info_set_tensor_type (in_info, 0, ML_TENSOR_TYPE_UINT8);
+
+  out_dim[0] = 1;
   out_dim[1] = 1;
   out_dim[2] = 1;
   out_dim[3] = 1;
@@ -2073,15 +2129,22 @@ TEST (nnstreamer_capi_singleshot, failure_01_n)
   ml_tensors_info_set_tensor_type (out_info, 0, ML_TENSOR_TYPE_UINT8);
   ml_tensors_info_set_tensor_dimension (out_info, 0, out_dim);
 
-  /* invalid file extension */
-  status = ml_single_open (&single, test_model, in_info, out_info,
-      ML_NNFW_TYPE_TENSORFLOW, ML_NNFW_HW_ANY);
+  /* invalid output dimension */
+  status = ml_single_open (&single, test_model, NULL, out_info,
+      ML_NNFW_TYPE_TENSORFLOW_LITE, ML_NNFW_HW_ANY);
   EXPECT_EQ (status, ML_ERROR_INVALID_PARAMETER);
 
-  /* invalid handle */
-  status = ml_single_close (single);
+  out_dim[0] = 1001;
+  ml_tensors_info_set_tensor_dimension (out_info, 0, out_dim);
+  ml_tensors_info_set_tensor_type (out_info, 0, ML_TENSOR_TYPE_UINT16);
+
+  /* invalid output type */
+  status = ml_single_open (&single, test_model, NULL, out_info,
+      ML_NNFW_TYPE_TENSORFLOW_LITE, ML_NNFW_HW_ANY);
   EXPECT_EQ (status, ML_ERROR_INVALID_PARAMETER);
 
+  ml_tensors_info_set_tensor_type (out_info, 0, ML_TENSOR_TYPE_UINT8);
+
   /* Successfully opened unknown fw type (tf-lite) */
   status = ml_single_open (&single, test_model, in_info, out_info,
       ML_NNFW_TYPE_ANY, ML_NNFW_HW_ANY);
@@ -2096,6 +2159,72 @@ TEST (nnstreamer_capi_singleshot, failure_01_n)
 }
 
 /**
+ * @brief Test NNStreamer single shot (tensorflow-lite)
+ * @detail Open model (dynamic dimension is supported)
+ */
+TEST (nnstreamer_capi_singleshot, open_dynamic)
+{
+  ml_single_h single;
+  ml_tensors_info_h in_info, out_info;
+  ml_tensor_dimension in_dim, out_dim;
+  ml_tensor_type_e type = ML_TENSOR_TYPE_UNKNOWN;
+  unsigned int count = 0;
+  int status;
+
+  const gchar *root_path = g_getenv ("NNSTREAMER_BUILD_ROOT_PATH");
+  gchar *test_model;
+
+  /* supposed to run test in build directory */
+  if (root_path == NULL)
+    root_path = "..";
+
+  /* dynamic dimension supported */
+  test_model = g_build_filename (root_path, "tests", "test_models", "models",
+      "add.tflite", NULL);
+  ASSERT_TRUE (g_file_test (test_model, G_FILE_TEST_EXISTS));
+
+  ml_tensors_info_create (&in_info);
+
+  in_dim[0] = 5;
+  in_dim[1] = 1;
+  in_dim[2] = 1;
+  in_dim[3] = 1;
+  ml_tensors_info_set_count (in_info, 1);
+  ml_tensors_info_set_tensor_type (in_info, 0, ML_TENSOR_TYPE_FLOAT32);
+  ml_tensors_info_set_tensor_dimension (in_info, 0, in_dim);
+
+  /* open with input tensor info (1:1:1:1 > 5:1:1:1) */
+  status = ml_single_open (&single, test_model, in_info, NULL,
+      ML_NNFW_TYPE_TENSORFLOW_LITE, ML_NNFW_HW_ANY);
+  EXPECT_EQ (status, ML_ERROR_NONE);
+
+  /* validate output info */
+  status = ml_single_get_output_info (single, &out_info);
+  EXPECT_EQ (status, ML_ERROR_NONE);
+
+  status = ml_tensors_info_get_count (out_info, &count);
+  EXPECT_EQ (status, ML_ERROR_NONE);
+  EXPECT_EQ (count, 1U);
+
+  status = ml_tensors_info_get_tensor_type (out_info, 0, &type);
+  EXPECT_EQ (status, ML_ERROR_NONE);
+  EXPECT_EQ (type, ML_TENSOR_TYPE_FLOAT32);
+
+  ml_tensors_info_get_tensor_dimension (out_info, 0, out_dim);
+  EXPECT_EQ (out_dim[0], 5U);
+  EXPECT_EQ (out_dim[1], 1U);
+  EXPECT_EQ (out_dim[2], 1U);
+  EXPECT_EQ (out_dim[3], 1U);
+
+  status = ml_single_close (single);
+  EXPECT_EQ (status, ML_ERROR_NONE);
+
+  g_free (test_model);
+  ml_tensors_info_destroy (in_info);
+  ml_tensors_info_destroy (out_info);
+}
+
+/**
  * @brief Structure containing values to run single shot
  */
 typedef struct {