Line data Source code
1 : /* SPDX-License-Identifier: LGPL-2.1-only */
2 : /**
3 : * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved.
4 : *
5 : * @file tensor_data.c
6 : * @date 10 Mar 2021
7 : * @brief Internal functions to handle various tensor type and value.
8 : * @see http://github.com/nnstreamer/nnstreamer
9 : * @author Jaeyun Jung <jy1210.jung@samsung.com>
10 : * @bug No known bugs except for NYI items
11 : */
12 :
13 : #include <math.h>
14 : #include "tensor_data.h"
15 : #include "nnstreamer_log.h"
16 : #include "nnstreamer_plugin_api.h"
17 :
18 : /**
19 : * @brief Macro to set data in struct.
20 : */
21 : #define td_set_data(td,v,dtype) do { \
22 : (td)->data._##dtype = *((dtype *) v); \
23 : } while (0)
24 :
25 : /**
26 : * @brief Macro to get data from struct.
27 : */
28 : #define td_get_data(td,v,dtype) do { \
29 : *((dtype *) v) = (td)->data._##dtype; \
30 : } while (0)
31 :
32 : /**
33 : * @brief Macro for typecast.
34 : */
35 : #define td_typecast_to(td,itype,otype) do { \
36 : itype in_val = (td)->data._##itype; \
37 : otype out_val = (otype) in_val; \
38 : (td)->data._##otype = out_val; \
39 : } while (0)
40 :
41 : #ifdef FLOAT16_SUPPORT
42 : #define td_typecast_to_fromf16(td,otype) do { \
43 : float16 in_val = (td)->data._float16; \
44 : otype out_val = (otype) in_val; \
45 : (td)->data._##otype = out_val; \
46 : } while (0)
47 : #else /* FLOAT16_SUPPORT */
48 : #define td_typecast_to_fromf16(td,itype) do { \
49 : nns_loge ("Your nnstreamer binary is built without -DFLOAT16_SUPPORT option; thus float16 is not supported.\n"); \
50 : g_assert (0); \
51 : } while (0)
52 : #endif
53 :
54 : #define td_typecast(td,otype) do { \
55 : switch ((td)->type) { \
56 : case _NNS_INT32: td_typecast_to (td, int32_t, otype); break; \
57 : case _NNS_UINT32: td_typecast_to (td, uint32_t, otype); break; \
58 : case _NNS_INT16: td_typecast_to (td, int16_t, otype); break; \
59 : case _NNS_UINT16: td_typecast_to (td, uint16_t, otype); break; \
60 : case _NNS_INT8: td_typecast_to (td, int8_t, otype); break; \
61 : case _NNS_UINT8: td_typecast_to (td, uint8_t, otype); break; \
62 : case _NNS_FLOAT64: td_typecast_to (td, double, otype); break; \
63 : case _NNS_FLOAT32: td_typecast_to (td, float, otype); break; \
64 : case _NNS_FLOAT16: td_typecast_to_fromf16 (td, otype); break; \
65 : case _NNS_INT64: td_typecast_to (td, int64_t, otype); break; \
66 : case _NNS_UINT64: td_typecast_to (td, uint64_t, otype); break; \
67 : default: g_assert (0); break; \
68 : } \
69 : } while (0)
70 :
71 : /**
72 : * @brief Set tensor element data with given type.
73 : * @param td struct for tensor data
74 : * @param type tensor type
75 : * @param value pointer of tensor element value
76 : * @return TRUE if no error
77 : */
78 : gboolean
79 3785079 : gst_tensor_data_set (tensor_data_s * td, tensor_type type, gpointer value)
80 : {
81 3785079 : g_return_val_if_fail (td != NULL, FALSE);
82 3785079 : g_return_val_if_fail (value != NULL, FALSE);
83 :
84 3785079 : td->data._int64_t = 0;
85 3785079 : td->type = _NNS_END;
86 :
87 3785079 : switch (type) {
88 114 : case _NNS_INT32:
89 114 : td_set_data (td, value, int32_t);
90 114 : break;
91 5051 : case _NNS_UINT32:
92 5051 : td_set_data (td, value, uint32_t);
93 5051 : break;
94 16 : case _NNS_INT16:
95 16 : td_set_data (td, value, int16_t);
96 16 : break;
97 24 : case _NNS_UINT16:
98 24 : td_set_data (td, value, uint16_t);
99 24 : break;
100 5016 : case _NNS_INT8:
101 5016 : td_set_data (td, value, int8_t);
102 5016 : break;
103 2868606 : case _NNS_UINT8:
104 2868606 : td_set_data (td, value, uint8_t);
105 2868606 : break;
106 686143 : case _NNS_FLOAT64:
107 686143 : td_set_data (td, value, double);
108 686143 : break;
109 220056 : case _NNS_FLOAT32:
110 220056 : td_set_data (td, value, float);
111 220056 : break;
112 0 : case _NNS_FLOAT16:
113 : #ifdef FLOAT16_SUPPORT
114 : td_set_data (td, value, float16);
115 : break;
116 : #else
117 0 : nns_loge
118 : ("NNStreamer requires -DFLOAT16_SUPPORT as a build option to enable float16 type. This binary does not have float16 feature enabled; thus, float16 type is not supported in this instance.\n");
119 0 : return FALSE;
120 : #endif
121 37 : case _NNS_INT64:
122 37 : td_set_data (td, value, int64_t);
123 37 : break;
124 16 : case _NNS_UINT64:
125 16 : td_set_data (td, value, uint64_t);
126 16 : break;
127 0 : default:
128 0 : nns_logw ("Unknown tensor type %d", type);
129 0 : return FALSE;
130 : }
131 :
132 3785079 : td->type = type;
133 3785079 : return TRUE;
134 : }
135 :
136 : /**
137 : * @brief Get tensor element value.
138 : * @param td struct for tensor data
139 : * @param value pointer of tensor element value
140 : * @return TRUE if no error
141 : */
142 : gboolean
143 3784930 : gst_tensor_data_get (tensor_data_s * td, gpointer value)
144 : {
145 3784930 : g_return_val_if_fail (td != NULL, FALSE);
146 3784930 : g_return_val_if_fail (value != NULL, FALSE);
147 :
148 3784930 : switch (td->type) {
149 15390 : case _NNS_INT32:
150 15390 : td_get_data (td, value, int32_t);
151 15390 : break;
152 20434 : case _NNS_UINT32:
153 20434 : td_get_data (td, value, uint32_t);
154 20434 : break;
155 15375 : case _NNS_INT16:
156 15375 : td_get_data (td, value, int16_t);
157 15375 : break;
158 15375 : case _NNS_UINT16:
159 15375 : td_get_data (td, value, uint16_t);
160 15375 : break;
161 20375 : case _NNS_INT8:
162 20375 : td_get_data (td, value, int8_t);
163 20375 : break;
164 591375 : case _NNS_UINT8:
165 591375 : td_get_data (td, value, uint8_t);
166 591375 : break;
167 2975741 : case _NNS_FLOAT64:
168 2975741 : td_get_data (td, value, double);
169 2975741 : break;
170 100115 : case _NNS_FLOAT32:
171 100115 : td_get_data (td, value, float);
172 100115 : break;
173 0 : case _NNS_FLOAT16:
174 : #ifdef FLOAT16_SUPPORT
175 : td_get_data (td, value, float16);
176 : break;
177 : #else
178 0 : nns_loge
179 : ("NNStreamer requires -DFLOAT16_SUPPORT as a build option to enable float16 type. This binary does not have float16 feature enabled; thus, float16 type is not supported in this instance.\n");
180 0 : return FALSE;
181 : #endif
182 15375 : case _NNS_INT64:
183 15375 : td_get_data (td, value, int64_t);
184 15375 : break;
185 15375 : case _NNS_UINT64:
186 15375 : td_get_data (td, value, uint64_t);
187 15375 : break;
188 0 : default:
189 0 : nns_logw ("Unknown tensor type %d", td->type);
190 0 : return FALSE;
191 : }
192 :
193 3784930 : return TRUE;
194 : }
195 :
196 : /**
197 : * @brief Typecast tensor element data.
198 : * @param td struct for tensor data
199 : * @param type tensor type to be transformed
200 : * @return TRUE if no error
201 : */
202 : gboolean
203 3869638 : gst_tensor_data_typecast (tensor_data_s * td, tensor_type type)
204 : {
205 : gboolean is_float;
206 :
207 3869638 : g_return_val_if_fail (td != NULL, FALSE);
208 :
209 : /* do nothing when transform to same type */
210 3869638 : if (td->type != type) {
211 3549645 : is_float = (td->type == _NNS_FLOAT32 || td->type == _NNS_FLOAT64
212 7319320 : || td->type == _NNS_FLOAT16);
213 :
214 3769675 : switch (type) {
215 15419 : case _NNS_INT32:
216 15419 : td_typecast (td, int32_t);
217 15419 : break;
218 20418 : case _NNS_UINT32:
219 20418 : if (is_float) {
220 5015 : td_typecast (td, int32_t);
221 5015 : td->type = _NNS_INT32;
222 : }
223 20418 : td_typecast (td, uint32_t);
224 20418 : break;
225 15378 : case _NNS_INT16:
226 15378 : td_typecast (td, int16_t);
227 15378 : break;
228 15378 : case _NNS_UINT16:
229 15378 : if (is_float) {
230 15 : td_typecast (td, int16_t);
231 15 : td->type = _NNS_INT16;
232 : }
233 15378 : td_typecast (td, uint16_t);
234 15378 : break;
235 20378 : case _NNS_INT8:
236 20378 : td_typecast (td, int8_t);
237 20378 : break;
238 576078 : case _NNS_UINT8:
239 576078 : if (is_float) {
240 576031 : td_typecast (td, int8_t);
241 576031 : td->type = _NNS_INT8;
242 : }
243 576078 : td_typecast (td, uint8_t);
244 576078 : break;
245 2975728 : case _NNS_FLOAT64:
246 2975728 : td_typecast (td, double);
247 2975728 : break;
248 100145 : case _NNS_FLOAT32:
249 100145 : td_typecast (td, float);
250 100145 : break;
251 0 : case _NNS_FLOAT16:
252 : #ifdef FLOAT16_SUPPORT
253 : td_typecast (td, float16);
254 : #else
255 0 : nns_loge
256 : ("NNStreamer requires -DFLOAT16_SUPPORT as a build option to enable float16 type. This binary does not have float16 feature enabled; thus, float16 type is not supported in this instance.\n");
257 0 : return FALSE;
258 : #endif
259 : break;
260 15375 : case _NNS_INT64:
261 15375 : td_typecast (td, int64_t);
262 15375 : break;
263 15378 : case _NNS_UINT64:
264 15378 : if (is_float) {
265 15 : td_typecast (td, int64_t);
266 15 : td->type = _NNS_INT64;
267 : }
268 15378 : td_typecast (td, uint64_t);
269 15378 : break;
270 0 : default:
271 0 : nns_logw ("Unknown tensor type %d", type);
272 0 : return FALSE;
273 : }
274 :
275 3769675 : td->type = type;
276 : }
277 :
278 3869638 : return TRUE;
279 : }
280 :
281 : /**
282 : * @brief Typecast tensor element value.
283 : * @param input pointer of input tensor data
284 : * @param in_type input tensor type
285 : * @param output pointer of output tensor data
286 : * @param out_type output tensor type
287 : * @return TRUE if no error
288 : */
289 : gboolean
290 3723390 : gst_tensor_data_raw_typecast (gpointer input, tensor_type in_type,
291 : gpointer output, tensor_type out_type)
292 : {
293 : tensor_data_s td;
294 :
295 7446780 : g_return_val_if_fail (input != NULL, FALSE);
296 3723390 : g_return_val_if_fail (output != NULL, FALSE);
297 3723390 : g_return_val_if_fail (in_type != _NNS_END, FALSE);
298 3723390 : g_return_val_if_fail (out_type != _NNS_END, FALSE);
299 :
300 3723390 : gst_tensor_data_set (&td, in_type, input);
301 3723390 : gst_tensor_data_typecast (&td, out_type);
302 3723390 : gst_tensor_data_get (&td, output);
303 3723390 : return TRUE;
304 : }
305 :
306 : /**
307 : * @brief Calculate average value of the tensor.
308 : * @param raw pointer of raw tensor data
309 : * @param length byte size of raw tensor data
310 : * @param type tensor type
311 : * @param result double pointer for average value of given tensor. Caller should release allocated memory.
312 : * @return TRUE if no error
313 : */
314 : gboolean
315 26 : gst_tensor_data_raw_average (gpointer raw, gsize length, tensor_type type,
316 : gdouble ** result)
317 : {
318 : gdouble value, average;
319 : gulong i, num;
320 : gsize element_size;
321 : guint8 *data;
322 :
323 52 : g_return_val_if_fail (raw != NULL, FALSE);
324 26 : g_return_val_if_fail (length > 0, FALSE);
325 26 : g_return_val_if_fail (type != _NNS_END, FALSE);
326 :
327 26 : element_size = gst_tensor_get_element_size (type);
328 26 : num = length / element_size;
329 :
330 26 : average = 0.0;
331 26 : *result = (gdouble *) g_try_malloc0 (sizeof (gdouble));
332 26 : if (*result == NULL) {
333 0 : nns_loge ("Failed to allocate memory for calculating average");
334 0 : return FALSE;
335 : }
336 :
337 2209722 : for (i = 0; i < num; ++i) {
338 : /* extract value and typecast to double */
339 2209696 : data = (guint8 *) raw + element_size * i;
340 2209696 : gst_tensor_data_raw_typecast (data, type, &value, _NNS_FLOAT64);
341 :
342 2209696 : average = (value - average) / (i + 1) + average;
343 : }
344 :
345 26 : **result = average;
346 :
347 26 : return TRUE;
348 : }
349 :
350 : /**
351 : * @brief Calculate average value of the tensor per channel (the first dim).
352 : * @param raw pointer of raw tensor data
353 : * @param length byte size of raw tensor data
354 : * @param type tensor type
355 : * @param tensor_dim tensor dimension
356 : * @param results double array contains average values of each channel. Caller should release allocated array.
357 : * @return TRUE if no error
358 : */
359 : gboolean
360 8 : gst_tensor_data_raw_average_per_channel (gpointer raw, gsize length,
361 : tensor_type type, tensor_dim dim, gdouble ** results)
362 : {
363 : gdouble value, average;
364 : gulong ch, i, num, offset;
365 : gsize element_size;
366 : guint8 *data;
367 :
368 16 : g_return_val_if_fail (raw != NULL, FALSE);
369 8 : g_return_val_if_fail (length > 0, FALSE);
370 8 : g_return_val_if_fail (dim[0] > 0, FALSE);
371 8 : g_return_val_if_fail (type != _NNS_END, FALSE);
372 :
373 8 : element_size = gst_tensor_get_element_size (type);
374 8 : num = length / element_size;
375 :
376 8 : offset = dim[0];
377 8 : num = num / offset;
378 8 : *results = (gdouble *) g_try_malloc0 (sizeof (gdouble) * offset);
379 8 : if (*results == NULL) {
380 0 : nns_loge ("Failed to allocate memory for calculating average");
381 0 : return FALSE;
382 : }
383 :
384 408 : for (ch = 0; ch < offset; ++ch) {
385 400 : average = 0.0;
386 40400 : for (i = 0; i < num; ++i) {
387 : /* extract value and typecast to double */
388 40000 : data = (guint8 *) raw + element_size * ((i * offset) + ch);
389 40000 : gst_tensor_data_raw_typecast (data, type, &value, _NNS_FLOAT64);
390 40000 : average = (value - average) / (i + 1) + average;
391 : }
392 :
393 400 : (*results)[ch] = average;
394 : }
395 :
396 8 : return TRUE;
397 : }
398 :
399 : /**
400 : * @brief Calculate standard deviation of the tensor.
401 : * @param raw pointer of raw tensor data
402 : * @param length byte size of raw tensor data
403 : * @param type tensor type
404 : * @param average average value of given tensor
405 : * @param result double pointer for standard deviation of given tensor. Caller should release allocated memory.
406 : * @return TRUE if no error
407 : */
408 : gboolean
409 4 : gst_tensor_data_raw_std (gpointer raw, gsize length, tensor_type type,
410 : gdouble * average, gdouble ** result)
411 : {
412 : gdouble value, std;
413 : gulong i, num;
414 : gsize element_size;
415 : guint8 *data;
416 :
417 8 : g_return_val_if_fail (raw != NULL, FALSE);
418 4 : g_return_val_if_fail (length > 0, FALSE);
419 4 : g_return_val_if_fail (type != _NNS_END, FALSE);
420 :
421 4 : element_size = gst_tensor_get_element_size (type);
422 4 : num = length / element_size;
423 4 : *result = (gdouble *) g_try_malloc0 (sizeof (gdouble));
424 4 : if (*result == NULL) {
425 0 : nns_loge ("Failed to allocate memory for calculating standard deviation");
426 0 : return FALSE;
427 : }
428 :
429 4 : std = 0.0;
430 20004 : for (i = 0; i < num; ++i) {
431 : /* extract value and typecast to double */
432 20000 : data = (guint8 *) raw + element_size * i;
433 20000 : gst_tensor_data_raw_typecast (data, type, &value, _NNS_FLOAT64);
434 :
435 20000 : std += pow (value - *average, 2) / num;
436 : }
437 :
438 4 : std = (std != 0.0) ? sqrt (std) : (1e-10);
439 4 : **result = std;
440 :
441 4 : return TRUE;
442 : }
443 :
444 : /**
445 : * @brief Calculate standard deviation of the tensor per channel (the first dim).
446 : * @param raw pointer of raw tensor data
447 : * @param length byte size of raw tensor data
448 : * @param type tensor type
449 : * @param tensor_dim tensor dimension
450 : * @param averages average values of given tensor per-channel
451 : * @param results double array contains standard deviation of each channel. Caller should release allocated array.
452 : * @return TRUE if no error
453 : */
454 : gboolean
455 4 : gst_tensor_data_raw_std_per_channel (gpointer raw, gsize length,
456 : tensor_type type, tensor_dim dim, gdouble * averages, gdouble ** results)
457 : {
458 : gdouble value, std;
459 : gulong ch, i, num, offset;
460 : gsize element_size;
461 : guint8 *data;
462 :
463 8 : g_return_val_if_fail (raw != NULL, FALSE);
464 4 : g_return_val_if_fail (length > 0, FALSE);
465 4 : g_return_val_if_fail (dim[0] > 0, FALSE);
466 4 : g_return_val_if_fail (type != _NNS_END, FALSE);
467 :
468 4 : element_size = gst_tensor_get_element_size (type);
469 4 : num = length / element_size;
470 :
471 4 : offset = dim[0];
472 4 : num = num / offset;
473 4 : *results = (gdouble *) g_try_malloc0 (sizeof (gdouble) * offset);
474 4 : if (*results == NULL) {
475 0 : nns_loge ("Failed to allocate memory for calculating standard deviation");
476 0 : return FALSE;
477 : }
478 :
479 204 : for (ch = 0; ch < offset; ++ch) {
480 200 : std = 0.0;
481 20200 : for (i = 0; i < num; ++i) {
482 : /* extract value and typecast to double */
483 20000 : data = (guint8 *) raw + element_size * ((i * offset) + ch);
484 20000 : gst_tensor_data_raw_typecast (data, type, &value, _NNS_FLOAT64);
485 20000 : std += pow (value - averages[ch], 2) / num;
486 : }
487 :
488 200 : std = (std != 0.0) ? sqrt (std) : (1e-10);
489 200 : (*results)[ch] = std;
490 : }
491 :
492 4 : return TRUE;
493 : }
|