[Tests] Add tests for increasing rank
authorYelin Jeong <yelini.jeong@samsung.com>
Thu, 29 Dec 2022 01:45:16 +0000 (10:45 +0900)
committerSangjung Woo <again4you@gmail.com>
Thu, 6 Apr 2023 02:18:17 +0000 (11:18 +0900)
This patch changes hardcoded ranks and adds higher rank testdata.

Signed-off-by: Yelin Jeong <yelini.jeong@samsung.com>
18 files changed:
tests/common/unittest_common.cc
tests/nnstreamer_converter/runTest.sh
tests/nnstreamer_example/custom_example_average/nnstreamer_customfilter_example_average.c
tests/nnstreamer_example/custom_example_passthrough/nnstreamer_customfilter_example_passthrough.c
tests/nnstreamer_example/custom_example_scaler/nnstreamer_customfilter_example_scaler.c
tests/nnstreamer_example/custom_example_scaler/nnstreamer_customfilter_example_scaler_allocator.c
tests/nnstreamer_filter_pytorch/generateTest.py [new file with mode: 0644]
tests/nnstreamer_filter_pytorch/runTest.sh
tests/nnstreamer_filter_single/unittest_filter_single.cc
tests/nnstreamer_filter_tensorflow2_lite/runTest.sh
tests/nnstreamer_if/unittest_if.cc
tests/nnstreamer_plugins/unittest_plugins.cc
tests/test_models/models/custom_decoder.py
tests/test_models/models/passthrough.py
tests/test_models/models/sample_4x4x4x4x4_two_input_one_output.pt [new file with mode: 0644]
tests/test_models/models/sample_4x4x4x4x4_two_input_one_output.tflite [new file with mode: 0644]
tests/test_models/models/scaler.py
tests/transform_dimchg/runTest.sh

index d54aac3..a62d3e1 100644 (file)
@@ -350,6 +350,100 @@ TEST (commonGetTensorDimension, case4)
 }
 
 /**
+ * @brief Test for tensor dimension.
+ */
+TEST (commonGetTensorDimension, case5)
+{
+  tensor_dim dim;
+  gchar *dim_str;
+  guint rank;
+
+  rank = gst_tensor_parse_dimension ("345:123:433:177:851", dim);
+  EXPECT_EQ (rank, 5U);
+  EXPECT_EQ (dim[0], 345U);
+  EXPECT_EQ (dim[1], 123U);
+  EXPECT_EQ (dim[2], 433U);
+  EXPECT_EQ (dim[3], 177U);
+  EXPECT_EQ (dim[4], 851U);
+
+  dim_str = gst_tensor_get_dimension_string (dim);
+  EXPECT_TRUE (gst_tensor_dimension_string_is_equal (dim_str, "345:123:433:177:851"));
+  g_free (dim_str);
+}
+
+/**
+ * @brief Test for tensor dimension.
+ */
+TEST (commonGetTensorDimension, case6)
+{
+  tensor_dim dim;
+  gchar *dim_str;
+  guint rank;
+
+  rank = gst_tensor_parse_dimension ("345:123:433:177:851:369", dim);
+  EXPECT_EQ (rank, 6U);
+  EXPECT_EQ (dim[0], 345U);
+  EXPECT_EQ (dim[1], 123U);
+  EXPECT_EQ (dim[2], 433U);
+  EXPECT_EQ (dim[3], 177U);
+  EXPECT_EQ (dim[4], 851U);
+  EXPECT_EQ (dim[5], 369U);
+
+  dim_str = gst_tensor_get_dimension_string (dim);
+  EXPECT_TRUE (gst_tensor_dimension_string_is_equal (dim_str, "345:123:433:177:851:369"));
+  g_free (dim_str);
+}
+
+/**
+ * @brief Test for tensor dimension.
+ */
+TEST (commonGetTensorDimension, case7)
+{
+  tensor_dim dim;
+  gchar *dim_str;
+  guint rank;
+
+  rank = gst_tensor_parse_dimension ("345:123:433:177:851:369:456", dim);
+  EXPECT_EQ (rank, 7U);
+  EXPECT_EQ (dim[0], 345U);
+  EXPECT_EQ (dim[1], 123U);
+  EXPECT_EQ (dim[2], 433U);
+  EXPECT_EQ (dim[3], 177U);
+  EXPECT_EQ (dim[4], 851U);
+  EXPECT_EQ (dim[5], 369U);
+  EXPECT_EQ (dim[6], 456U);
+
+  dim_str = gst_tensor_get_dimension_string (dim);
+  EXPECT_TRUE (gst_tensor_dimension_string_is_equal (dim_str, "345:123:433:177:851:369:456"));
+  g_free (dim_str);
+}
+
+/**
+ * @brief Test for tensor dimension.
+ */
+TEST (commonGetTensorDimension, case8)
+{
+  tensor_dim dim;
+  gchar *dim_str;
+  guint rank;
+
+  rank = gst_tensor_parse_dimension ("345:123:433:177:851:369:456:91", dim);
+  EXPECT_EQ (rank, 8U);
+  EXPECT_EQ (dim[0], 345U);
+  EXPECT_EQ (dim[1], 123U);
+  EXPECT_EQ (dim[2], 433U);
+  EXPECT_EQ (dim[3], 177U);
+  EXPECT_EQ (dim[4], 851U);
+  EXPECT_EQ (dim[5], 369U);
+  EXPECT_EQ (dim[6], 456U);
+  EXPECT_EQ (dim[7], 91U);
+
+  dim_str = gst_tensor_get_dimension_string (dim);
+  EXPECT_TRUE (gst_tensor_dimension_string_is_equal (dim_str, "345:123:433:177:851:369:456:91"));
+  g_free (dim_str);
+}
+
+/**
  * @brief Test to copy tensor info.
  */
 TEST (commonTensorInfo, copyTensor)
@@ -439,11 +533,19 @@ fill_tensors_info_for_test (GstTensorsInfo *info1, GstTensorsInfo *info2)
   info1->info[0].dimension[1] = info2->info[0].dimension[1] = 3;
   info1->info[0].dimension[2] = info2->info[0].dimension[2] = 1;
   info1->info[0].dimension[3] = info2->info[0].dimension[3] = 1;
+  info1->info[0].dimension[4] = info2->info[0].dimension[4] = 2;
+  info1->info[0].dimension[5] = info2->info[0].dimension[5] = 3;
+  info1->info[0].dimension[6] = info2->info[0].dimension[6] = 1;
+  info1->info[0].dimension[7] = info2->info[0].dimension[7] = 1;
 
   info1->info[1].dimension[0] = info2->info[1].dimension[0] = 5;
   info1->info[1].dimension[1] = info2->info[1].dimension[1] = 5;
   info1->info[1].dimension[2] = info2->info[1].dimension[2] = 1;
   info1->info[1].dimension[3] = info2->info[1].dimension[3] = 1;
+  info1->info[1].dimension[4] = info2->info[1].dimension[4] = 5;
+  info1->info[1].dimension[5] = info2->info[1].dimension[5] = 5;
+  info1->info[1].dimension[6] = info2->info[1].dimension[6] = 1;
+  info1->info[1].dimension[7] = info2->info[1].dimension[7] = 1;
 }
 
 /**
index 040659c..ff92878 100644 (file)
@@ -24,6 +24,7 @@ if [ "$SKIPGEN" == "YES" ]; then
 else
     echo "Test Case Generation Started"
     python3 generateGoldenTestResult.py
+    python3 ../nnstreamer_filter_pytorch/generateTest.py
     sopath=$1
 fi
 convertBMP2PNG
@@ -87,6 +88,10 @@ callCompareTest testcase08.golden testcase08.log 6-2 "PNG Stream Test" 0 0
 gstTest "--gst-plugin-path=${PATH_TO_PLUGIN} videotestsrc num-buffers=1 ! videoscale ! videoconvert ! video/x-raw,format=RGB,framerate=30/1,height=300,width=300 ! tensor_converter ! other/tensor,dimension=3:300:300,types=uint8,framerate=30/1,format=static ! fakesink" 7-1 0 0 $PERFORMANCE
 gstTest "--gst-plugin-path=${PATH_TO_PLUGIN} videotestsrc num-buffers=1 ! videoscale ! videoconvert ! video/x-raw,format=RGB,framerate=30/1,height=300,width=300 ! tensor_converter ! other/tensors,num_tensors=1,dimension=3:300:300,types=uint8,framerate=30/1,format=static ! fakesink" 7-2 0 0 $PERFORMANCE
 
-rm *.log *.bmp *.png *.golden
+# Test with high dimension (rank>4)
+gstTest "--gst-plugin-path=${PATH_TO_PLUGIN} filesrc location=\"test_00.dat\" blocksize=-1 ! application/octet-stream ! tensor_converter input-dim=4:4:4:4:4 input-type=float32 ! fakesink" 8-1 0 0 $PERFORMANCE
+gstTest "--gst-plugin-path=${PATH_TO_PLUGIN} filesrc location=\"test_01.dat\" blocksize=-1 ! application/octet-stream ! tensor_converter input-dim=3:10:10:4:5:6 input-type=uint8 ! fakesink" 8-2 0 0 $PERFORMANCE
+
+rm *.log *.bmp *.png *.golden *.dat
 
 report
index 1a324d9..834aadd 100644 (file)
@@ -131,9 +131,6 @@ pt_invoke (void *private_data, const GstTensorFilterProperties * prop,
   assert (input);
   assert (output);
 
-  /* This assumes the limit is 4 */
-  assert (NNS_TENSOR_RANK_LIMIT == 4);
-
   assert (prop->input_meta.info[0].dimension[0] ==
       prop->output_meta.info[0].dimension[0]);
   assert (prop->input_meta.info[0].dimension[3] ==
index 0533c39..5279d1d 100644 (file)
 #define D2     (280)
 #define D3     (40)
 #define D4     (1)
+#define D5     (1)
+#define D6     (1)
+#define D7     (1)
+#define D8     (1)
 
 /**
  * @brief _pt_data
@@ -52,6 +56,10 @@ pt_init (const GstTensorFilterProperties * prop)
   data->info.dimension[1] = D2;
   data->info.dimension[2] = D3;
   data->info.dimension[3] = D4;
+  data->info.dimension[4] = D5;
+  data->info.dimension[5] = D6;
+  data->info.dimension[6] = D7;
+  data->info.dimension[7] = D8;
   data->info.type = _NNS_UINT8;
 
   return data;
@@ -80,7 +88,7 @@ get_inputDim (void *private_data, const GstTensorFilterProperties * prop,
   UNUSED (prop);
 
   assert (data);
-  assert (NNS_TENSOR_RANK_LIMIT >= 3);
+  assert (NNS_TENSOR_RANK_LIMIT >= 7);
 
   info->num_tensors = 1;
   gst_tensor_info_copy (&info->info[0], &data->info);
@@ -98,7 +106,7 @@ get_outputDim (void *private_data, const GstTensorFilterProperties * prop,
   UNUSED (prop);
 
   assert (data);
-  assert (NNS_TENSOR_RANK_LIMIT >= 3);
+  assert (NNS_TENSOR_RANK_LIMIT >= 7);
 
   info->num_tensors = 1;
   gst_tensor_info_copy (&info->info[0], &data->info);
index 2c235df..f2ca5c1 100644 (file)
@@ -138,9 +138,6 @@ pt_invoke (void *private_data, const GstTensorFilterProperties * prop,
   assert (input);
   assert (output);
 
-  /* This assumes the limit is 4 */
-  assert (NNS_TENSOR_RANK_LIMIT == 4);
-
   assert (prop->input_meta.info[0].dimension[0] ==
       prop->output_meta.info[0].dimension[0]);
   assert (prop->input_meta.info[0].dimension[3] ==
index 505d962..253c6c7 100644 (file)
@@ -144,9 +144,6 @@ pt_allocate_invoke (void *private_data,
   output[0].data = malloc (size);
   assert (output[0].data != NULL);
 
-  /* This assumes the limit is 4 */
-  assert (NNS_TENSOR_RANK_LIMIT == 4);
-
   assert (prop->input_meta.info[0].dimension[0] ==
       prop->output_meta.info[0].dimension[0]);
   assert (prop->input_meta.info[0].dimension[3] ==
diff --git a/tests/nnstreamer_filter_pytorch/generateTest.py b/tests/nnstreamer_filter_pytorch/generateTest.py
new file mode 100644 (file)
index 0000000..eb42577
--- /dev/null
@@ -0,0 +1,24 @@
+#!/usr/bin/env python3
+
+##
+# SPDX-License-Identifier: LGPL-2.1-only
+#
+# Copyright (C) 2022 Samsung Electronics
+#
+# @file generateTest.py
+# @brief generate test data and golden test result
+# @author Yelin Jeong <yelini.jeong@samsung.com>
+
+import numpy as np
+
+def save_test_data(filename, shape, type):
+    data = np.random.uniform(-100, 100, shape).astype(type)
+    with open(filename, 'wb') as file:
+        file.write(data.tobytes())
+
+    golden = data*2
+    with open(filename + '.golden', 'wb') as file:
+        file.write(golden.tobytes())
+
+save_test_data('test_00.dat', [4,4,4,4,4], np.float32)
+save_test_data('test_01.dat', [3,10,10,4,5,6], np.int8)
index b01a101..8b3a0a3 100644 (file)
@@ -67,6 +67,15 @@ else
     fi
 fi
 
+if [ "$SKIPGEN" == "YES" ]; then
+    echo "Test Case Generation Skipped"
+    sopath=$2
+else
+    echo "Test Case Generation Started"
+    python3 generateTest.py
+    sopath=$1
+fi
+
 gstTest "--gst-plugin-path=${PATH_TO_PLUGIN} filesrc location=${PATH_TO_IMAGE} ! pngdec ! videoscale ! imagefreeze ! videoconvert ! video/x-raw,format=GRAY8,framerate=0/1 ! tensor_converter ! tensor_filter framework=pytorch model=${PATH_TO_MODEL} input=1:28:28:1 inputtype=uint8 output=10:1:1:1 outputtype=uint8 ! filesink location=tensorfilter.out.log" 1 0 0 $PERFORMANCE
 python3 checkLabel.py tensorfilter.out.log ${PATH_TO_IMAGE}
 testResult $? 1 "Golden test comparison" 0 1
@@ -132,7 +141,40 @@ gstTest "--gst-plugin-path=${PATH_TO_PLUGIN} videotestsrc num-buffers=2 ! videos
 
 gstTest "--gst-plugin-path=${PATH_TO_PLUGIN} videotestsrc num-buffers=2 ! videoscale ! videoconvert ! video/x-raw,width=3,height=4,format=GRAY8,framerate=0/1 ! tensor_converter ! tensor_transform mode=transpose option=2:1:0:3 ! other/tensors,num_tensors=1,dimensions=4:3:1:1,types=uint8,format=static,framerate=0/1 ! tensor_transform mode=typecast option=float32 ! tee name=t t. ! queue ! mux.sink_0 t. ! queue ! mux.sink_1  tensor_mux name=mux sync_mode=nosync ! queue ! tensor_filter framework=pytorch model=${PATH_TO_MODEL} input=4:3:1:1.4:3:1:1 inputtype=float32.float32 output=4:3:1:1.4:3:1:1 outputtype=float32.float32 ! other/tensors,num_tensors=2,dimensions=4:3.4:3 ! filesink location=tensorfilter.out.log" 10-2 0 0 $PERFORMANCE
 
+PATH_TO_MODEL="../test_models/models/sample_4x4x4x4x4_two_input_one_output.pt"
+# This model is made with below simple python script:
+#
+# import torch
+# class MyCell(torch.nn.Module):
+#     def __init__(self):
+#         super(MyCell, self).__init__()
+#     def forward(self, x, y):
+#         z = x + y
+#         return z
+
+# my_cell = MyCell()
+# x, y = torch.rand(4, 4, 4, 4, 4), torch.rand(4, 4, 4, 4, 4)
+# traced_cell = torch.jit.trace(my_cell, (x, y))
+# traced_cell(x, y)
+# traced_cell.save('sample_4x4x4x4x4_two_input_one_output.pt')
+
+# Test multiple input output tensors
+
+## correct input/output info
+gstTest "--gst-plugin-path=${PATH_TO_PLUGIN} filesrc location=\"test_00.dat\" blocksize=-1 ! application/octet-stream ! tensor_converter input-dim=4:4:4:4:4 input-type=float32 ! tee name=t t. ! queue ! mux.sink_0 t. ! queue ! mux.sink_1  tensor_mux name=mux sync_mode=nosync ! queue ! tensor_filter framework=pytorch model=${PATH_TO_MODEL} input=4:4:4:4:4,4:4:4:4:4 inputtype=float32.float32 output=4:4:4:4:4 outputtype=float32 ! filesink location=tensorfilter.out.log" 11-1 0 0 $PERFORMANCE
+callCompareTest test_00.dat.golden tensorfilter.out.log 11-1 "Compare 11-1" 1 0
+
+## correct input/output info with full dimension
+gstTest "--gst-plugin-path=${PATH_TO_PLUGIN} filesrc location=\"test_00.dat\" blocksize=-1 ! application/octet-stream ! tensor_converter input-dim=4:4:4:4:4:1:1:1 input-type=float32 ! tee name=t t. ! queue ! mux.sink_0 t. ! queue ! mux.sink_1  tensor_mux name=mux sync_mode=nosync ! queue ! tensor_filter framework=pytorch model=${PATH_TO_MODEL} input=4:4:4:4:4:1:1:1,4:4:4:4:4:1:1:1 inputtype=float32.float32 output=4:4:4:4:4:1:1:1 outputtype=float32 ! filesink location=tensorfilter.out.log" 11-2 0 0 $PERFORMANCE
+callCompareTest test_00.dat.golden tensorfilter.out.log 11-2 "Compare 11-2" 1 0
+
+## wrong input info
+gstTest "--gst-plugin-path=${PATH_TO_PLUGIN} filesrc location=\"test_00.dat\" blocksize=-1 ! application/octet-stream ! tensor_converter input-dim=4:4:4:4:4 input-type=uint8 ! tee name=t t. ! queue ! mux.sink_0 t. ! queue ! mux.sink_1  tensor_mux name=mux sync_mode=nosync ! queue ! tensor_filter framework=pytorch model=${PATH_TO_MODEL} input=4:4:4:4:2:2,4:4:4:4:2:2 inputtype=uint8.uint8 output=4:4:4:4:4 outputtype=uint8 ! filesink location=tensorfilter.out.log" 12_n 0 1 $PERFORMANCE
+
+## wrong output info
+gstTest "--gst-plugin-path=${PATH_TO_PLUGIN} filesrc location=\"test_00.dat\" blocksize=-1 ! application/octet-stream ! tensor_converter input-dim=4:4:4:4:4 input-type=uint8 ! tee name=t t. ! queue ! mux.sink_0 t. ! queue ! mux.sink_1  tensor_mux name=mux sync_mode=nosync ! queue ! tensor_filter framework=pytorch model=${PATH_TO_MODEL} input=4:4:4:4:4,4:4:4:4:4 inputtype=uint8.uint8 output=4:2:2:4:4 outputtype=uint8 ! filesink location=tensorfilter.out.log" 13_n 0 1 $PERFORMANCE
+
 # Cleanup
-rm info *.log *.golden
+rm info *.log *.golden *.dat
 
 report
index a3a7188..1130ba2 100644 (file)
@@ -202,6 +202,133 @@ TEST_F (NNSFilterSingleTest, invalidProperty_n)
 }
 #endif /* ENABLE_TENSORFLOW_LITE */
 
+#ifdef ENABLE_TENSORFLOW2_LITE
+/**
+ * @brief Test Fixture class for a tensor-filter single functionality with high rank.
+ */
+class NNSFilterSingleTestExtended : public::testing::Test
+{
+protected:
+  GTensorFilterSingle *single;
+  GTensorFilterSingleClass *klass;
+  GstTensorMemory input[2];
+  GstTensorMemory output;
+  gboolean loaded;
+
+public:
+  /**
+   * @brief Construct a new NNSFilterSingleTestExtended object
+   */
+  NNSFilterSingleTestExtended ()
+    : single (nullptr), klass (nullptr), loaded (FALSE)
+  {
+    input[0].data = input[1].data = output.data = nullptr;
+    input[0].size = input[1].size = output.size = 0;
+  }
+
+  /**
+   * @brief SetUp method for each test case
+   */
+  void SetUp () override
+  {
+    g_autofree gchar *model_file = nullptr;
+    gsize length = 4 * 4 * 4 * 4 * 4;
+    guint i;
+    const gchar *root_path = g_getenv ("NNSTREAMER_SOURCE_ROOT_PATH");
+
+    input[0].size = length * 4;
+    input[1].size = length * 4;
+    output.size = length * 4;
+
+    single = (GTensorFilterSingle *) g_object_new (G_TYPE_TENSOR_FILTER_SINGLE, NULL);
+    klass = (GTensorFilterSingleClass *) g_type_class_ref (G_TYPE_TENSOR_FILTER_SINGLE);
+
+    /* supposed to run test in build directory */
+    if (root_path == NULL)
+      root_path = "..";
+
+    model_file = g_build_filename (root_path, "tests", "test_models", "models",
+        "sample_4x4x4x4x4_two_input_one_output.tflite", NULL);
+    ASSERT_TRUE (g_file_test (model_file, G_FILE_TEST_EXISTS));
+
+    input[0].data = g_malloc0(sizeof(gfloat)*length);
+    input[1].data = g_malloc0(sizeof(gfloat)*length);
+
+    for (i = 0; i < length ; i++) {
+      ((gfloat*)input[0].data)[i] = i;
+      ((gfloat*)input[1].data)[i] = i + 1;
+    }
+
+    g_object_set (G_OBJECT (single), "framework", "tensorflow-lite",
+        "model", model_file, NULL);
+    loaded = TRUE;
+  }
+
+  /**
+   * @brief TearDown method for each test case
+   */
+  void TearDown () override
+  {
+    g_type_class_unref (klass);
+    g_object_unref (single);
+    g_free (input[0].data);
+    g_free (input[1].data);
+    g_free (output.data);
+  }
+};
+
+/**
+ * @brief Test to invoke tf-lite model.
+ */
+TEST_F (NNSFilterSingleTestExtended, invoke_p)
+{
+  guint i, length = 4 * 4 * 4 * 4 * 4;
+  ASSERT_TRUE (this->loaded);
+
+  /* invoke the model and check output result */
+  EXPECT_TRUE (klass->invoke (single, input, &output, TRUE));
+
+  for (i = 0 ; i < length ; i++)
+    EXPECT_EQ (((gfloat *)output.data)[i], (((gfloat*)input[0].data)[i]  + ((gfloat*)input[1].data)[i]));
+
+  EXPECT_TRUE (klass->input_configured (single));
+  EXPECT_TRUE (klass->output_configured (single));
+  EXPECT_FALSE (klass->allocate_in_invoke (single));
+
+  klass->destroy_notify (single, &output);
+}
+
+/**
+ * @brief Test to set invalid info.
+ */
+TEST_F (NNSFilterSingleTestExtended, setInvalidInfo_n)
+{
+  GstTensorsInfo in_info, out_info;
+  gst_tensors_info_init (&in_info);
+  gst_tensors_info_init (&out_info);
+
+  ASSERT_TRUE (this->loaded);
+  EXPECT_TRUE (klass->start (single));
+
+  /* valid tensor info */
+  in_info.num_tensors = 2U;
+  in_info.info[0].type = _NNS_FLOAT32;
+  gst_tensor_parse_dimension ("4:4:4:4:4", in_info.info[0].dimension);
+  in_info.info[1].type = _NNS_FLOAT32;
+  gst_tensor_parse_dimension ("4:4:4:4:4", in_info.info[1].dimension);
+  EXPECT_TRUE (klass->set_input_info (single, &in_info, &out_info) == 0);
+
+  /* request to set invalid tensor info */
+  in_info.num_tensors = 1U;
+  EXPECT_FALSE (klass->set_input_info (single, &in_info, &out_info) == 0);
+
+  EXPECT_TRUE (klass->stop (single));
+  gst_tensors_info_free (&in_info);
+  gst_tensors_info_free (&out_info);
+}
+
+#endif /* ENABLE_TENSORFLOW2_LITE */
+
 /**
  * @brief Test to start before initializing.
  */
index addbcc4..f28d4b0 100644 (file)
@@ -65,6 +65,15 @@ else
     fi
 fi
 
+if [ "$SKIPGEN" == "YES" ]; then
+    echo "Test Case Generation Skipped"
+    sopath=$2
+else
+    echo "Test Case Generation Started"
+    python3 ../nnstreamer_filter_pytorch/generateTest.py
+    sopath=$1
+fi
+
 PATH_TO_MODEL="../test_models/models/mobilenet_v1_1.0_224_quant.tflite"
 PATH_TO_LABEL="../test_models/labels/labels.txt"
 PATH_TO_IMAGE="../test_models/data/orange.png"
@@ -201,7 +210,31 @@ gstTest "--gst-plugin-path=${PATH_TO_PLUGIN} filesrc location=${PATH_TO_IMAGE} !
 python3 checkLabel.py tensorfilter.out.log ${PATH_TO_LABEL} orange
 testResult $? 5 "Golden test comparison" 0 1
 
+PATH_TO_MODEL="../test_models/models/sample_4x4x4x4x4_two_input_one_output.tflite"
+# This model is made with below simple python script:
+#
+# import tensorflow as tf
+# from tensorflow import keras
+# from tensorflow.keras.layers import *
+# from tensorflow.keras import *
+
+# x1 = Input((4,4,4,4,4))
+# x2 = Input((4,4,4,4,4))
+# output = Add()([x1,x2])
+# model = Model(inputs=[x1,x2],outputs=[output])
+# model.compile()
+# model.summary()
+
+# converter = tf.lite.TFLiteConverter.from_keras_model(model)
+# tflite_model = converter.convert()
+
+# with open("tflite_model.tflite", "wb") as f:
+#     f.write(tflite_model)
+
+gstTest "--gst-plugin-path=${PATH_TO_PLUGIN} multifilesrc location=\"test_00.dat\" blocksize=-1 num_buffers=2 ! application/octet-stream ! tensor_converter input-dim=4:4:4:4:4 input-type=float32 ! tee name=t t. ! queue ! mux.sink_0 t. ! queue ! mux.sink_1  tensor_mux name=mux sync_mode=nosync ! queue ! tensor_filter framework=tensorflow2-lite model=${PATH_TO_MODEL} ! multifilesink location=tensorfilter.out.log" 6 0 0 $PERFORMANCE
+callCompareTest test_00.dat.golden tensorfilter.out.log 6 "Compare 6" 1 0
+
 # Cleanup
-rm info *.log
+rm info *.log *.dat *.golden
 
 report
index 32a4320..c9ccdc0 100644 (file)
@@ -99,7 +99,7 @@ TEST (tensorIfProp, properties0)
   EXPECT_EQ (TIFCV_A_VALUE, int_val);
 
   g_object_get (tif_handle, "compared-value-option", &str_val, NULL);
-  EXPECT_STREQ ("0:2:1:1,0", str_val);
+  EXPECT_STREQ ("0:2:1:1:0:0:0:0,0", str_val);
   g_free (str_val);
 
   g_object_get (tif_handle, "supplied-value", &str_val, NULL);
index dc514d3..ae57978 100644 (file)
@@ -2140,7 +2140,7 @@ TEST (testTensorTransform, arithmeticFlexTensor)
 }
 
 /**
- * @brief Test data for tensor_aggregator (2 frames with dimension 3:4:2:2)
+ * @brief Test data for tensor_aggregator (2 frames with dimension 3:4:2:2 or 3:2:2:2:2)
  */
 const gint aggr_test_frames[2][48]
     = { { 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111, 1112,
@@ -2484,6 +2484,236 @@ TEST (testTensorAggregator, aggregate5)
 }
 
 /**
+ * @brief Test for tensor_aggregator (concatenate 2 frames with frames-dim 4, out-dimension 3:2:2:2:4)
+ */
+TEST (testTensorAggregator, aggregate6)
+{
+  GstHarness *h;
+  GstTensorsConfig config;
+  guint i;
+  gsize data_in_size;
+
+  h = gst_harness_new ("tensor_aggregator");
+
+  g_object_set (h->element, "frames-out", 2, "frames-dim", 4, NULL);
+
+  /* input tensor info */
+  gst_tensors_config_init (&config);
+  config.info.num_tensors = 1;
+  config.info.info[0].type = _NNS_INT32;
+  gst_tensor_parse_dimension ("3:2:2:2:2", config.info.info[0].dimension);
+  config.rate_n = 0;
+  config.rate_d = 1;
+
+  gst_harness_set_src_caps (h, gst_tensors_caps_from_config (&config));
+  data_in_size = gst_tensors_info_get_size (&config.info, 0);
+
+  /* push buffers */
+  for (i = 0; i < 2; i++) {
+    _aggregator_test_push_buffer (h, aggr_test_frames[i], data_in_size);
+  }
+
+  /* get output buffer */
+  const gint expected[96] = { 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108,
+    1109, 1110, 1111, 1112, 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1120,
+    1121, 1122, 1123, 1124, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208,
+    1209, 1210, 1211, 1212, 1213, 1214, 1215, 1216, 1217, 1218, 1219, 1220, 1221,
+    1222, 1223, 1224, 2101, 2102, 2103, 2104, 2105, 2106, 2107, 2108, 2109, 2110,
+    2111, 2112, 2113, 2114, 2115, 2116, 2117, 2118, 2119, 2120, 2121, 2122, 2123,
+    2124, 2201, 2202, 2203, 2204, 2205, 2206, 2207, 2208, 2209, 2210, 2211, 2212,
+    2213, 2214, 2215, 2216, 2217, 2218, 2219, 2220, 2221, 2222, 2223, 2224 };
+
+  _aggregator_test_check_output (h, expected, 96);
+
+  EXPECT_EQ (gst_harness_buffers_received (h), 1U);
+  gst_harness_teardown (h);
+}
+
+/**
+ * @brief Test for tensor_aggregator (concatenate 2 frames with frames-dim 3, out-dimension 3:2:2:4:2)
+ */
+TEST (testTensorAggregator, aggregate7)
+{
+  GstHarness *h;
+  GstTensorsConfig config;
+  guint i;
+  gsize data_in_size;
+
+  h = gst_harness_new ("tensor_aggregator");
+
+  g_object_set (h->element, "frames-out", 2, "frames-dim", 3, NULL);
+
+  /* input tensor info */
+  gst_tensors_config_init (&config);
+  config.info.num_tensors = 1;
+  config.info.info[0].type = _NNS_INT32;
+  gst_tensor_parse_dimension ("3:2:2:2:2", config.info.info[0].dimension);
+  config.rate_n = 0;
+  config.rate_d = 1;
+
+  gst_harness_set_src_caps (h, gst_tensors_caps_from_config (&config));
+  data_in_size = gst_tensors_info_get_size (&config.info, 0);
+
+  /* push buffers */
+  for (i = 0; i < 2; i++) {
+    _aggregator_test_push_buffer (h, aggr_test_frames[i], data_in_size);
+  }
+
+  /* get output buffer */
+  const gint expected[96] = { 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108,
+    1109, 1110, 1111, 1112, 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1120,
+    1121, 1122, 1123, 1124, 2101, 2102, 2103, 2104, 2105, 2106, 2107, 2108,
+    2109, 2110, 2111, 2112, 2113, 2114, 2115, 2116, 2117, 2118, 2119, 2120, 2121,
+    2122, 2123, 2124, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, 1210,
+    1211, 1212, 1213, 1214, 1215, 1216, 1217, 1218, 1219, 1220, 1221, 1222, 1223,
+    1224, 2201, 2202, 2203, 2204, 2205, 2206, 2207, 2208, 2209, 2210, 2211, 2212,
+    2213, 2214, 2215, 2216, 2217, 2218, 2219, 2220, 2221, 2222, 2223, 2224 };
+
+  _aggregator_test_check_output (h, expected, 96);
+
+  EXPECT_EQ (gst_harness_buffers_received (h), 1U);
+  gst_harness_teardown (h);
+}
+
+/**
+ * @brief Test for tensor_aggregator (concatenate 2 frames with frames-dim 2, out-dimension 3:2:4:2:2)
+ */
+TEST (testTensorAggregator, aggregate8)
+{
+  GstHarness *h;
+  GstTensorsConfig config;
+  guint i;
+  gsize data_in_size;
+
+  h = gst_harness_new ("tensor_aggregator");
+
+  g_object_set (h->element, "frames-out", 2, "frames-dim", 2, NULL);
+
+  /* input tensor info */
+  gst_tensors_config_init (&config);
+  config.info.num_tensors = 1;
+  config.info.info[0].type = _NNS_INT32;
+  gst_tensor_parse_dimension ("3:2:2:2:2", config.info.info[0].dimension);
+  config.rate_n = 0;
+  config.rate_d = 1;
+
+  gst_harness_set_src_caps (h, gst_tensors_caps_from_config (&config));
+  data_in_size = gst_tensors_info_get_size (&config.info, 0);
+
+  /* push buffers */
+  for (i = 0; i < 2; i++) {
+    _aggregator_test_push_buffer (h, aggr_test_frames[i], data_in_size);
+  }
+
+  /* get output buffer */
+  const gint expected[96] = { 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108,
+    1109, 1110, 1111, 1112, 2101, 2102, 2103, 2104, 2105, 2106, 2107, 2108,
+    2109, 2110, 2111, 2112, 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1120,
+    1121, 1122, 1123, 1124, 2113, 2114, 2115, 2116, 2117, 2118, 2119, 2120, 2121,
+    2122, 2123, 2124, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, 1210,
+    1211, 1212, 2201, 2202, 2203, 2204, 2205, 2206, 2207, 2208, 2209, 2210, 2211,
+    2212, 1213, 1214, 1215, 1216, 1217, 1218, 1219, 1220, 1221, 1222, 1223, 1224,
+    2213, 2214, 2215, 2216, 2217, 2218, 2219, 2220, 2221, 2222, 2223, 2224 };
+
+  _aggregator_test_check_output (h, expected, 96);
+
+  EXPECT_EQ (gst_harness_buffers_received (h), 1U);
+  gst_harness_teardown (h);
+}
+
+/**
+ * @brief Test for tensor_aggregator (concatenate 2 frames with frames-dim 1, out-dimension 3:4:2:2:2)
+ */
+TEST (testTensorAggregator, aggregate9)
+{
+  GstHarness *h;
+  GstTensorsConfig config;
+  guint i;
+  gsize data_in_size;
+
+  h = gst_harness_new ("tensor_aggregator");
+
+  g_object_set (h->element, "frames-out", 2, "frames-dim", 1, NULL);
+
+  /* input tensor info */
+  gst_tensors_config_init (&config);
+  config.info.num_tensors = 1;
+  config.info.info[0].type = _NNS_INT32;
+  gst_tensor_parse_dimension ("3:2:2:2:2", config.info.info[0].dimension);
+  config.rate_n = 0;
+  config.rate_d = 1;
+
+  gst_harness_set_src_caps (h, gst_tensors_caps_from_config (&config));
+  data_in_size = gst_tensors_info_get_size (&config.info, 0);
+
+  /* push buffers */
+  for (i = 0; i < 2; i++) {
+    _aggregator_test_push_buffer (h, aggr_test_frames[i], data_in_size);
+  }
+
+  /* get output buffer */
+  const gint expected[96] = { 1101, 1102, 1103, 1104, 1105, 1106, 2101, 2102,
+    2103, 2104, 2105, 2106, 1107, 1108, 1109, 1110, 1111, 1112, 2107, 2108,
+    2109, 2110, 2111, 2112, 1113, 1114, 1115, 1116, 1117, 1118, 2113, 2114,
+    2115, 2116, 2117, 2118, 1119, 1120, 1121, 1122, 1123, 1124, 2119, 2120, 2121,
+    2122, 2123, 2124, 1201, 1202, 1203, 1204, 1205, 1206, 2201, 2202, 2203, 2204,
+    2205, 2206, 1207, 1208, 1209, 1210, 1211, 1212, 2207, 2208, 2209, 2210, 2211,
+    2212, 1213, 1214, 1215, 1216, 1217, 1218, 2213, 2214, 2215, 2216, 2217, 2218,
+    1219, 1220, 1221, 1222, 1223, 1224, 2219, 2220, 2221, 2222, 2223, 2224 };
+
+  _aggregator_test_check_output (h, expected, 96);
+
+  EXPECT_EQ (gst_harness_buffers_received (h), 1U);
+  gst_harness_teardown (h);
+}
+
+/**
+ * @brief Test for tensor_aggregator (concatenate 2 frames with frames-dim 0, out-dimension 6:2:2:2:2)
+ */
+TEST (testTensorAggregator, aggregate10)
+{
+  GstHarness *h;
+  GstTensorsConfig config;
+  guint i;
+  gsize data_in_size;
+
+  h = gst_harness_new ("tensor_aggregator");
+
+  g_object_set (h->element, "frames-out", 2, "frames-dim", 0, NULL);
+
+  /* input tensor info */
+  gst_tensors_config_init (&config);
+  config.info.num_tensors = 1;
+  config.info.info[0].type = _NNS_INT32;
+  gst_tensor_parse_dimension ("3:2:2:2:2", config.info.info[0].dimension);
+  config.rate_n = 0;
+  config.rate_d = 1;
+
+  gst_harness_set_src_caps (h, gst_tensors_caps_from_config (&config));
+  data_in_size = gst_tensors_info_get_size (&config.info, 0);
+
+  /* push buffers */
+  for (i = 0; i < 2; i++) {
+    _aggregator_test_push_buffer (h, aggr_test_frames[i], data_in_size);
+  }
+
+  /* get output buffer */
+  const gint expected[96] = { 1101, 1102, 1103, 2101, 2102, 2103, 1104, 1105,
+    1106, 2104, 2105, 2106, 1107, 1108, 1109, 2107, 2108, 2109, 1110, 1111,
+    1112, 2110, 2111, 2112, 1113, 1114, 1115, 2113, 2114, 2115, 1116, 1117,
+    1118, 2116, 2117, 2118, 1119, 1120, 1121, 2119, 2120, 2121, 1122, 1123, 1124,
+    2122, 2123, 2124, 1201, 1202, 1203, 2201, 2202, 2203, 1204, 1205, 1206, 2204,
+    2205, 2206, 1207, 1208, 1209, 2207, 2208, 2209, 1210, 1211, 1212, 2210, 2211,
+    2212, 1213, 1214, 1215, 2213, 2214, 2215, 1216, 1217, 1218, 2216, 2217, 2218,
+    1219, 1220, 1221, 2219, 2220, 2221, 1222, 1223, 1224, 2222, 2223, 2224 };
+
+  _aggregator_test_check_output (h, expected, 96);
+
+  EXPECT_EQ (gst_harness_buffers_received (h), 1U);
+  gst_harness_teardown (h);
+}
+
+/**
  * @brief Test for tensor_aggregator (flush old data in aggregator)
  */
 TEST (testTensorAggregator, flushData)
index b357485..3c8ec32 100644 (file)
@@ -71,7 +71,7 @@ class CustomDecoder(object):
                     fbb.String("")
                     fbb.Int(ttype)
                     with fbb.TypedVector():
-                        for j in range(4):
+                        for j in range(8):
                             fbb.Int(dims[j])
                     fbb.Blob(raw_data[i])
 
index af8e683..af94d0c 100644 (file)
@@ -14,6 +14,10 @@ D1 = 3
 D2 = 280
 D3 = 40
 D4 = 1
+D5 = 1
+D6 = 1
+D7 = 1
+D8 = 1
 
 
 ##
@@ -22,8 +26,8 @@ class CustomFilter(object):
     ##
     # @brief  The constructor for custom filter: passthrough
     def __init__(self, *args):
-        self.input_dims = [nns.TensorShape([D1, D2, D3, D4], np.uint8)]
-        self.output_dims = [nns.TensorShape([D1, D2, D3, D4], np.uint8)]
+        self.input_dims = [nns.TensorShape([D1, D2, D3, D4, D5, D6, D7, D8], np.uint8)]
+        self.output_dims = [nns.TensorShape([D1, D2, D3, D4, D5, D6, D7, D8], np.uint8)]
 
     ##
     # @brief  python callback: getInputDim
diff --git a/tests/test_models/models/sample_4x4x4x4x4_two_input_one_output.pt b/tests/test_models/models/sample_4x4x4x4x4_two_input_one_output.pt
new file mode 100644 (file)
index 0000000..8145bb4
Binary files /dev/null and b/tests/test_models/models/sample_4x4x4x4x4_two_input_one_output.pt differ
diff --git a/tests/test_models/models/sample_4x4x4x4x4_two_input_one_output.tflite b/tests/test_models/models/sample_4x4x4x4x4_two_input_one_output.tflite
new file mode 100644 (file)
index 0000000..4fc02ce
Binary files /dev/null and b/tests/test_models/models/sample_4x4x4x4x4_two_input_one_output.tflite differ
index fc014f1..263f6b0 100644 (file)
@@ -65,7 +65,7 @@ class CustomFilter(object):
                     for c in range(out_dims[0]):
                         ix = int(x * in_dims[1] / out_dims[1])
                         iy = int(y * in_dims[2] / out_dims[2])
-                        output_tensor[z][y][x][c] = input_tensor[z][iy][ix][c]
+                        output_tensor[0][0][0][0][z][y][x][c] = input_tensor[0][0][0][0][z][iy][ix][c]
 
         # to 1-D array
         return [np.ravel(output_tensor)]
index 33bd8ee..1ccd80f 100644 (file)
@@ -65,6 +65,22 @@ testResult $? 2 "Golden test comparison 3-1" 0 1
 python3 checkResult.py dimchg0:b testcase03.direct.log testcase03_2.dimchg02.log 4 1024 1
 testResult $? 2 "Golden test comparison 3-2" 0 1
 
+# Test with rank 6 input
+gstTest "--gst-plugin-path=${PATH_TO_PLUGIN} filesrc location=\"test_01.dat\" blocksize=-1 ! application/octet-stream ! tensor_converter input-dim=3:10:10:4:5:6 input-type=int8 ! tee name=t ! queue ! tensor_transform mode=dimchg option=0:2 ! filesink location=\"testcase04.dimchg02.log\" sync=true t. ! queue ! filesink location=\"testcase04.direct.log\" sync=true" 4 0 0 $PERFORMANCE
+# dim1 = 3
+# rbs = 3 x 10 x 10
+# es = 1
+python3 checkResult.py dimchg0:b testcase04.direct.log testcase04.dimchg02.log 3 300 1
+testResult $? 4 "Golden test comparison" 0 1
+
+# Test with high(4) dimchg option
+gstTest "--gst-plugin-path=${PATH_TO_PLUGIN} filesrc location=\"test_01.dat\" blocksize=-1 ! application/octet-stream ! tensor_converter input-dim=3:10:10:4:5:6 input-type=int8 ! tee name=t ! queue ! tensor_transform mode=dimchg option=0:4 ! filesink location=\"testcase05.dimchg04.log\" sync=true t. ! queue ! filesink location=\"testcase05.direct.log\" sync=true" 5 0 0 $PERFORMANCE
+# dim1 = 3
+# rbs = 3 x 10 x 10 x 4 x 5
+# es = 1
+python3 checkResult.py dimchg0:b testcase05.direct.log testcase05.dimchg04.log 3 6000 1
+testResult $? 5 "Golden test comparison" 0 1
+
 rm *.log *.bmp *.png *.golden *.raw *.dat
 
 report