From 162b78bbf735fe82abf06ac0ab028c347aba87b4 Mon Sep 17 00:00:00 2001 From: Yongjoo Ahn Date: Thu, 1 Apr 2021 14:55:53 +0900 Subject: [PATCH] [tensor_data] Make tensor_data_raw_* return allocated memory - `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 --- gst/nnstreamer/tensor_data.c | 71 ++++++++++++------ gst/nnstreamer/tensor_data.h | 23 +++--- gst/nnstreamer/tensor_if/gsttensorif.c | 8 ++- gst/nnstreamer/tensor_transform/tensor_transform.c | 83 ++++++++++------------ 4 files changed, 104 insertions(+), 81 deletions(-) diff --git a/gst/nnstreamer/tensor_data.c b/gst/nnstreamer/tensor_data.c index a2a84b7..8ca623e 100644 --- a/gst/nnstreamer/tensor_data.c +++ b/gst/nnstreamer/tensor_data.c @@ -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; diff --git a/gst/nnstreamer/tensor_data.h b/gst/nnstreamer/tensor_data.h index 5383709..a9c77bc 100644 --- a/gst/nnstreamer/tensor_data.h +++ b/gst/nnstreamer/tensor_data.h @@ -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__ */ diff --git a/gst/nnstreamer/tensor_if/gsttensorif.c b/gst/nnstreamer/tensor_if/gsttensorif.c index c962f68..f09cea2 100644 --- a/gst/nnstreamer/tensor_if/gsttensorif.c +++ b/gst/nnstreamer/tensor_if/gsttensorif.c @@ -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; } diff --git a/gst/nnstreamer/tensor_transform/tensor_transform.c b/gst/nnstreamer/tensor_transform/tensor_transform.c index 8f689ef..77a75ad 100644 --- a/gst/nnstreamer/tensor_transform/tensor_transform.c +++ b/gst/nnstreamer/tensor_transform/tensor_transform.c @@ -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; } /** -- 2.7.4