[tensor_data] Make tensor_data_raw_* return allocated memory
authorYongjoo Ahn <yongjoo1.ahn@samsung.com>
Thu, 1 Apr 2021 05:55:53 +0000 (14:55 +0900)
committerMyungJoo Ham <myungjoo.ham@samsung.com>
Thu, 1 Apr 2021 10:13:25 +0000 (19:13 +0900)
- `gst_tensor_data_raw_*` get double pointer for result as input. And allocate memory for it.
- Correspond change in tensor_transform and gsttensorif
- Divide with N, not N - 1 when calculate standard deviation

Signed-off-by: Yongjoo Ahn <yongjoo1.ahn@samsung.com>
gst/nnstreamer/tensor_data.c
gst/nnstreamer/tensor_data.h
gst/nnstreamer/tensor_if/gsttensorif.c
gst/nnstreamer/tensor_transform/tensor_transform.c

index a2a84b7..8ca623e 100644 (file)
@@ -266,24 +266,32 @@ gst_tensor_data_raw_typecast (gpointer input, tensor_type in_type,
  * @param raw pointer of raw tensor data
  * @param length byte size of raw tensor data
  * @param type tensor type
- * @return average value
+ * @param result double pointer for average value of given tensor. Caller should release allocated memory.
+ * @return TRUE if no error
  */
-gdouble
-gst_tensor_data_raw_average (gpointer raw, gsize length, tensor_type type)
+gboolean
+gst_tensor_data_raw_average (gpointer raw, gsize length, tensor_type type,
+    gdouble ** result)
 {
   gdouble value, average;
   gulong i, num;
   gsize element_size;
   guint8 *data;
 
-  g_return_val_if_fail (raw != NULL, 0.0);
-  g_return_val_if_fail (length > 0, 0.0);
-  g_return_val_if_fail (type != _NNS_END, 0.0);
+  g_return_val_if_fail (raw != NULL, FALSE);
+  g_return_val_if_fail (length > 0, FALSE);
+  g_return_val_if_fail (type != _NNS_END, FALSE);
 
   element_size = gst_tensor_get_element_size (type);
   num = length / element_size;
 
   average = 0.0;
+  *result = (gdouble *) g_try_malloc0 (sizeof (gdouble));
+  if (*result == NULL) {
+    nns_loge ("Failed to allocate memory for calculating average");
+    return FALSE;
+  }
+
   for (i = 0; i < num; ++i) {
     /* extract value and typecast to double */
     data = (guint8 *) raw + element_size * i;
@@ -292,7 +300,9 @@ gst_tensor_data_raw_average (gpointer raw, gsize length, tensor_type type)
     average = (value - average) / (i + 1) + average;
   }
 
-  return average;
+  **result = average;
+
+  return TRUE;
 }
 
 /**
@@ -301,12 +311,12 @@ gst_tensor_data_raw_average (gpointer raw, gsize length, tensor_type type)
  * @param length byte size of raw tensor data
  * @param type tensor type
  * @param tensor_dim tensor dimension
- * @param results double array contains average values of each channel
+ * @param results double array contains average values of each channel. Caller should release allocated array.
  * @return TRUE if no error
  */
 gboolean
 gst_tensor_data_raw_average_per_channel (gpointer raw, gsize length,
-    tensor_type type, tensor_dim dim, gdouble * results)
+    tensor_type type, tensor_dim dim, gdouble ** results)
 {
   gdouble value, average;
   gulong ch, i, num, offset;
@@ -323,6 +333,11 @@ gst_tensor_data_raw_average_per_channel (gpointer raw, gsize length,
 
   offset = dim[0];
   num = num / offset;
+  *results = (gdouble *) g_try_malloc0 (sizeof (gdouble) * offset);
+  if (*results == NULL) {
+    nns_loge ("Failed to allocate memory for calculating average");
+    return FALSE;
+  }
 
   for (ch = 0; ch < offset; ++ch) {
     average = 0.0;
@@ -333,7 +348,7 @@ gst_tensor_data_raw_average_per_channel (gpointer raw, gsize length,
       average = (value - average) / (i + 1) + average;
     }
 
-    results[ch] = average;
+    (*results)[ch] = average;
   }
 
   return TRUE;
@@ -345,23 +360,29 @@ gst_tensor_data_raw_average_per_channel (gpointer raw, gsize length,
  * @param length byte size of raw tensor data
  * @param type tensor type
  * @param average average value of given tensor
- * @return standard deviation
+ * @param result double pointer for standard deviation of given tensor. Caller should release allocated memory.
+ * @return TRUE if no error
  */
-gdouble
+gboolean
 gst_tensor_data_raw_std (gpointer raw, gsize length, tensor_type type,
-    gdouble average)
+    gdouble * average, gdouble ** result)
 {
   gdouble value, std;
   gulong i, num;
   gsize element_size;
   guint8 *data;
 
-  g_return_val_if_fail (raw != NULL, 0.0);
-  g_return_val_if_fail (length > 0, 0.0);
-  g_return_val_if_fail (type != _NNS_END, 0.0);
+  g_return_val_if_fail (raw != NULL, FALSE);
+  g_return_val_if_fail (length > 0, FALSE);
+  g_return_val_if_fail (type != _NNS_END, FALSE);
 
   element_size = gst_tensor_get_element_size (type);
   num = length / element_size;
+  *result = (gdouble *) g_try_malloc0 (sizeof (gdouble));
+  if (*result == NULL) {
+    nns_loge ("Failed to allocate memory for calculating standard deviation");
+    return FALSE;
+  }
 
   std = 0.0;
   for (i = 0; i < num; ++i) {
@@ -369,12 +390,13 @@ gst_tensor_data_raw_std (gpointer raw, gsize length, tensor_type type,
     data = (guint8 *) raw + element_size * i;
     gst_tensor_data_raw_typecast (data, type, &value, _NNS_FLOAT64);
 
-    std += pow (value - average, 2) / (num - 1);
+    std += pow (value - *average, 2) / num;
   }
 
   std = (std != 0.0) ? sqrt (std) : (1e-10);
+  **result = std;
 
-  return std;
+  return TRUE;
 }
 
 /**
@@ -384,12 +406,12 @@ gst_tensor_data_raw_std (gpointer raw, gsize length, tensor_type type,
  * @param type tensor type
  * @param tensor_dim tensor dimension
  * @param averages average values of given tensor per-channel
- * @param results double array contains standard deviation of each channel
+ * @param results double array contains standard deviation of each channel. Caller should release allocated array.
  * @return TRUE if no error
  */
 gboolean
 gst_tensor_data_raw_std_per_channel (gpointer raw, gsize length,
-    tensor_type type, tensor_dim dim, gdouble * averages, gdouble * results)
+    tensor_type type, tensor_dim dim, gdouble * averages, gdouble ** results)
 {
   gdouble value, std;
   gulong ch, i, num, offset;
@@ -406,6 +428,11 @@ gst_tensor_data_raw_std_per_channel (gpointer raw, gsize length,
 
   offset = dim[0];
   num = num / offset;
+  *results = (gdouble *) g_try_malloc0 (sizeof (gdouble) * offset);
+  if (*results == NULL) {
+    nns_loge ("Failed to allocate memory for calculating standard deviation");
+    return FALSE;
+  }
 
   for (ch = 0; ch < offset; ++ch) {
     std = 0.0;
@@ -413,11 +440,11 @@ gst_tensor_data_raw_std_per_channel (gpointer raw, gsize length,
       /* extract value and typecast to double */
       data = (guint8 *) raw + element_size * ((i * offset) + ch);
       gst_tensor_data_raw_typecast (data, type, &value, _NNS_FLOAT64);
-      std += pow (value - averages[ch], 2) / (num - 1);
+      std += pow (value - averages[ch], 2) / num;
     }
 
     std = (std != 0.0) ? sqrt (std) : (1e-10);
-    results[ch] = std;
+    (*results)[ch] = std;
   }
 
   return TRUE;
index 5383709..a9c77bc 100644 (file)
@@ -71,10 +71,12 @@ gst_tensor_data_raw_typecast (gpointer input, tensor_type in_type,
  * @param raw pointer of raw tensor data
  * @param length byte size of raw tensor data
  * @param type tensor type
- * @return average value
+ * @param result double pointer for average value of given tensor. Caller should release allocated memory.
+ * @return TRUE if no error
  */
-extern gdouble
-gst_tensor_data_raw_average (gpointer raw, gsize length, tensor_type type);
+extern gboolean
+gst_tensor_data_raw_average (gpointer raw, gsize length, tensor_type type,
+    gdouble ** result);
 
 /**
  * @brief Calculate average value of the tensor per channel (the first dim).
@@ -82,12 +84,12 @@ gst_tensor_data_raw_average (gpointer raw, gsize length, tensor_type type);
  * @param length byte size of raw tensor data
  * @param type tensor type
  * @param tensor_dim tensor dimension
- * @param results double array contains average values of each channel
+ * @param results double array contains average values of each channel. Caller should release allocated array.
  * @return TRUE if no error
  */
 extern gboolean
 gst_tensor_data_raw_average_per_channel (gpointer raw, gsize length,
-    tensor_type type, tensor_dim dim, gdouble * results);
+    tensor_type type, tensor_dim dim, gdouble ** results);
 
 /**
  * @brief Calculate standard deviation of the tensor.
@@ -95,11 +97,12 @@ gst_tensor_data_raw_average_per_channel (gpointer raw, gsize length,
  * @param length byte size of raw tensor data
  * @param type tensor type
  * @param average average value of given tensor
- * @return standard deviation
+ * @param result double pointer for standard deviation of given tensor. Caller should release allocated memory.
+ * @return TRUE if no error
  */
-extern gdouble
+extern gboolean
 gst_tensor_data_raw_std (gpointer raw, gsize length, tensor_type type,
-    gdouble average);
+    gdouble * average, gdouble ** result);
 
 /**
  * @brief Calculate standard deviation of the tensor per channel (the first dim).
@@ -108,12 +111,12 @@ gst_tensor_data_raw_std (gpointer raw, gsize length, tensor_type type,
  * @param type tensor type
  * @param tensor_dim tensor dimension
  * @param averages average values of given tensor per-channel
- * @param results double array contains standard deviation of each channel
+ * @param results double array contains standard deviation of each channel. Caller should release allocated array.
  * @return TRUE if no error
  */
 extern gboolean
 gst_tensor_data_raw_std_per_channel (gpointer raw, gsize length, 
-    tensor_type type, tensor_dim dim, gdouble * averages, gdouble * results);
+    tensor_type type, tensor_dim dim, gdouble * averages, gdouble ** results);
 
 G_END_DECLS
 #endif /* __NNS_TENSOR_DATA_H__ */
index c962f68..f09cea2 100644 (file)
@@ -874,7 +874,7 @@ gst_tensor_if_get_tensor_average (GstTensorIf * tensor_if,
 {
   GstMemory *in_mem;
   GstMapInfo in_info;
-  double avg;
+  gdouble *avg = NULL;
   tensor_type type = tensor_if->in_config.info.info[nth].type;
 
   in_mem = gst_buffer_peek_memory (buf, nth);
@@ -883,12 +883,14 @@ gst_tensor_if_get_tensor_average (GstTensorIf * tensor_if,
     return FALSE;
   }
 
-  avg = gst_tensor_data_raw_average (in_info.data, in_info.size, type);
+  gst_tensor_data_raw_average (in_info.data, in_info.size, type, &avg);
 
   gst_memory_unmap (in_mem, &in_info);
 
-  gst_tensor_data_set (cv, _NNS_FLOAT64, &avg);
+  gst_tensor_data_set (cv, _NNS_FLOAT64, avg);
   gst_tensor_data_typecast (cv, type);
+
+  g_free (avg);
   return TRUE;
 }
 
index 8f689ef..77a75ad 100644 (file)
@@ -1240,27 +1240,42 @@ static GstFlowReturn
 gst_tensor_transform_stand (GstTensorTransform * filter,
     guint idx, const uint8_t * inptr, uint8_t * outptr)
 {
-  tensor_type in_tensor_type = filter->in_config.info.info[idx].type;
-  tensor_type out_tensor_type = filter->out_config.info.info[idx].type;
+  GstFlowReturn ret = GST_FLOW_OK;
+  GstTensorInfo *in_info, *out_info;
+  tensor_type in_tensor_type, out_tensor_type;
   gsize in_element_size, out_element_size, data_size, ch_size;
   gulong i, num, data_idx, ch;
-  gdouble tmp, average, std;
-  gdouble *avg_per_ch, *std_per_ch;
+  gdouble tmp, *average, *std;
+
+  in_info = &filter->in_config.info.info[idx];
+  out_info = &filter->out_config.info.info[idx];
+  in_tensor_type = in_info->type;
+  out_tensor_type = out_info->type;
 
   in_element_size = gst_tensor_get_element_size (in_tensor_type);
   out_element_size = gst_tensor_get_element_size (out_tensor_type);
-  num =
-      gst_tensor_get_element_count (filter->in_config.info.info[idx].dimension);
+  num = gst_tensor_get_element_count (in_info->dimension);
 
-  ch_size = filter->in_config.info.info[idx].dimension[0];
+  data_size = gst_tensor_info_get_size (in_info);
+  ch_size = in_info->dimension[0];
 
   /* calc average and std */
-  data_size = gst_tensor_info_get_size (&filter->in_config.info.info[idx]);
-  average = gst_tensor_data_raw_average ((gpointer) inptr, data_size,
-      in_tensor_type);
-  std =
+  average = std = NULL;
+  if (filter->data_stand.per_channel) {
+    gst_tensor_data_raw_average_per_channel ((gpointer) inptr, data_size,
+        in_tensor_type, in_info->dimension, &average);
+    /* calculate std only for default mode */
+    if (filter->data_stand.mode == STAND_DEFAULT)
+      gst_tensor_data_raw_std_per_channel ((gpointer) inptr, data_size,
+          in_tensor_type, in_info->dimension, average, &std);
+  } else {
+    gst_tensor_data_raw_average ((gpointer) inptr, data_size,
+        in_tensor_type, &average);
+    /* calculate std only for default mode */
+    if (filter->data_stand.mode == STAND_DEFAULT)
       gst_tensor_data_raw_std ((gpointer) inptr, data_size, in_tensor_type,
-      average);
+          average, &std);
+  }
 
   switch (filter->data_stand.mode) {
     case STAND_DEFAULT:
@@ -1271,44 +1286,26 @@ gst_tensor_transform_stand (GstTensorTransform * filter,
           gst_tensor_data_raw_typecast ((gpointer) (inptr + data_idx),
               in_tensor_type, &tmp, _NNS_FLOAT64);
 
-          tmp = fabs ((tmp - average) / std);
+          tmp = fabs ((tmp - *average) / *std);
 
           data_idx = out_element_size * i;
           gst_tensor_data_raw_typecast (&tmp, _NNS_FLOAT64,
               (gpointer) (outptr + data_idx), out_tensor_type);
         }
       } else {
-        avg_per_ch =
-            (gdouble *) g_malloc0 (sizeof (gdouble) *
-            filter->in_config.info.info[idx].dimension[0]);
-
-        gst_tensor_data_raw_average_per_channel ((gpointer) inptr, data_size,
-            in_tensor_type, filter->in_config.info.info[idx].dimension,
-            avg_per_ch);
-
-        std_per_ch =
-            (gdouble *) g_malloc0 (sizeof (gdouble) *
-            filter->in_config.info.info[idx].dimension[0]);
-        gst_tensor_data_raw_std_per_channel ((gpointer) inptr, data_size,
-            in_tensor_type, filter->in_config.info.info[idx].dimension,
-            avg_per_ch, std_per_ch);
-
         for (ch = 0; ch < ch_size; ++ch) {
           for (i = 0; i < num / ch_size; i++) {
             data_idx = in_element_size * ((i * ch_size) + ch);
             gst_tensor_data_raw_typecast ((gpointer) (inptr + data_idx),
                 in_tensor_type, &tmp, _NNS_FLOAT64);
 
-            tmp = fabs ((tmp - avg_per_ch[ch]) / std_per_ch[ch]);
+            tmp = fabs ((tmp - average[ch]) / std[ch]);
 
             data_idx = out_element_size * ((i * ch_size) + ch);
             gst_tensor_data_raw_typecast (&tmp, _NNS_FLOAT64,
                 (gpointer) (outptr + data_idx), out_tensor_type);
           }
         }
-
-        g_free (avg_per_ch);
-        g_free (std_per_ch);
       }
       break;
     }
@@ -1320,44 +1317,38 @@ gst_tensor_transform_stand (GstTensorTransform * filter,
           gst_tensor_data_raw_typecast ((gpointer) (inptr + data_idx),
               in_tensor_type, &tmp, _NNS_FLOAT64);
 
-          tmp -= average;
+          tmp -= *average;
+
           data_idx = out_element_size * i;
           gst_tensor_data_raw_typecast (&tmp, _NNS_FLOAT64,
               (gpointer) (outptr + data_idx), out_tensor_type);
         }
       } else {
-        avg_per_ch =
-            (gdouble *) g_malloc0 (sizeof (gdouble) *
-            filter->in_config.info.info[idx].dimension[0]);
-
-        gst_tensor_data_raw_average_per_channel ((gpointer) inptr, data_size,
-            in_tensor_type, filter->in_config.info.info[idx].dimension,
-            avg_per_ch);
-
         for (ch = 0; ch < ch_size; ++ch) {
           for (i = 0; i < num / ch_size; i++) {
             data_idx = in_element_size * ((i * ch_size) + ch);
             gst_tensor_data_raw_typecast ((gpointer) (inptr + data_idx),
                 in_tensor_type, &tmp, _NNS_FLOAT64);
 
-            tmp -= avg_per_ch[ch];
+            tmp -= average[ch];
 
             data_idx = out_element_size * ((i * ch_size) + ch);
             gst_tensor_data_raw_typecast (&tmp, _NNS_FLOAT64,
                 (gpointer) (outptr + data_idx), out_tensor_type);
           }
         }
-
-        g_free (avg_per_ch);
       }
       break;
     }
     default:
       GST_ERROR_OBJECT (filter, "Cannot identify mode\n");
-      return GST_FLOW_ERROR;
+      ret = GST_FLOW_ERROR;
   }
 
-  return GST_FLOW_OK;
+  g_free (average);
+  g_free (std);
+
+  return ret;
 }
 
 /**