Line data Source code
1 : /* SPDX-License-Identifier: LGPL-2.1-only */
2 : /**
3 : * GStreamer / NNStreamer Sparse Tensor support
4 : * Copyright (C) 2021 Yongjoo Ahn <yongjoo1.ahn@samsung.com>
5 : */
6 : /**
7 : * @file gsttensor_sparseutil.c
8 : * @date 27 Jul 2021
9 : * @brief Util functions for tensor_sparse encoder and decoder.
10 : * @see https://github.com/nnstreamer/nnstreamer
11 : * @author Yongjoo Ahn <yongjoo1.ahn@samsung.com>
12 : * @bug No known bugs except for NYI items
13 : */
14 :
15 : #include <string.h>
16 : #include <tensor_common.h>
17 : #include <tensor_data.h>
18 : #include "gsttensor_sparseutil.h"
19 :
20 : /**
21 : * @brief Make dense tensor with input sparse tensor.
22 : * @param[in,out] meta tensor meta structure to be updated
23 : * @param[in] mem gst-memory of sparse tensor data
24 : * @return pointer of GstMemory with dense tensor data or NULL on error. Caller should handle this newly allocated memory.
25 : */
26 : GstMemory *
27 36 : gst_tensor_sparse_to_dense (GstTensorMetaInfo * meta, GstMemory * mem)
28 : {
29 36 : GstMemory *dense = NULL;
30 : GstMapInfo map;
31 : guint i, nnz;
32 : guint8 *output, *input;
33 : guint *indices;
34 : gsize output_size, element_size;
35 :
36 36 : if (!gst_memory_map (mem, &map, GST_MAP_READ)) {
37 0 : nns_loge ("Failed to map given memory");
38 36 : return NULL;
39 : }
40 :
41 36 : if (!gst_tensor_meta_info_parse_header (meta, map.data)) {
42 1 : nns_loge ("Failed to parse meta info from given memory");
43 1 : goto done;
44 : }
45 :
46 35 : meta->format = _NNS_TENSOR_FORMAT_STATIC;
47 :
48 35 : element_size = gst_tensor_get_element_size (meta->type);
49 35 : output_size = gst_tensor_meta_info_get_data_size (meta);
50 :
51 35 : if (element_size == 0 || output_size == 0) {
52 0 : nns_loge ("Got invalid meta info");
53 0 : goto done;
54 : }
55 :
56 35 : output = (guint8 *) g_malloc0 (output_size);
57 :
58 35 : nnz = meta->sparse_info.nnz;
59 35 : input = map.data + gst_tensor_meta_info_get_header_size (meta);
60 35 : indices = (guint *) (input + element_size * nnz);
61 :
62 1498 : for (i = 0; i < nnz; ++i) {
63 1463 : switch (meta->type) {
64 6 : case _NNS_INT32:
65 6 : ((int32_t *) output)[indices[i]] = ((int32_t *) input)[i];
66 6 : break;
67 6 : case _NNS_UINT32:
68 6 : ((uint32_t *) output)[indices[i]] = ((uint32_t *) input)[i];
69 6 : break;
70 6 : case _NNS_INT16:
71 6 : ((int16_t *) output)[indices[i]] = ((int16_t *) input)[i];
72 6 : break;
73 6 : case _NNS_UINT16:
74 6 : ((uint16_t *) output)[indices[i]] = ((uint16_t *) input)[i];
75 6 : break;
76 6 : case _NNS_INT8:
77 6 : ((int8_t *) output)[indices[i]] = ((int8_t *) input)[i];
78 6 : break;
79 18 : case _NNS_UINT8:
80 18 : ((uint8_t *) output)[indices[i]] = ((uint8_t *) input)[i];
81 18 : break;
82 6 : case _NNS_FLOAT64:
83 6 : ((double *) output)[indices[i]] = ((double *) input)[i];
84 6 : break;
85 1397 : case _NNS_FLOAT32:
86 1397 : ((float *) output)[indices[i]] = ((float *) input)[i];
87 1397 : break;
88 6 : case _NNS_INT64:
89 6 : ((int64_t *) output)[indices[i]] = ((int64_t *) input)[i];
90 6 : break;
91 6 : case _NNS_UINT64:
92 6 : ((uint64_t *) output)[indices[i]] = ((uint64_t *) input)[i];
93 6 : break;
94 0 : default:
95 0 : nns_loge ("Error occurred during get tensor value");
96 0 : g_free (output);
97 0 : goto done;
98 : }
99 : }
100 :
101 35 : dense = gst_memory_new_wrapped (0, output, output_size, 0, output_size,
102 : output, g_free);
103 :
104 36 : done:
105 36 : gst_memory_unmap (mem, &map);
106 36 : return dense;
107 : }
108 :
109 : /**
110 : * @brief Make sparse tensor with input dense tensor.
111 : * @param[in,out] meta tensor meta structure to be updated
112 : * @param[in] mem gst-memory of dense tensor data
113 : * @return pointer of GstMemory with sparse tensor data or NULL on error. Caller should handle this newly allocated memory.
114 : */
115 : GstMemory *
116 77 : gst_tensor_sparse_from_dense (GstTensorMetaInfo * meta, GstMemory * mem)
117 : {
118 77 : GstMemory *sparse = NULL;
119 : GstMapInfo map;
120 77 : guint i, nnz = 0;
121 : guint8 *output;
122 : tensor_type data_type;
123 : void *values;
124 : guint *indices;
125 : gsize output_size, header_size, element_size;
126 : gulong element_count;
127 :
128 77 : if (!gst_memory_map (mem, &map, GST_MAP_READ)) {
129 0 : nns_loge ("Failed to map given memory");
130 77 : return NULL;
131 : }
132 :
133 77 : header_size = gst_tensor_meta_info_get_header_size (meta);
134 77 : element_size = gst_tensor_get_element_size (meta->type);
135 77 : element_count = gst_tensor_get_element_count (meta->dimension);
136 :
137 77 : if (element_size == 0 || element_count == 0) {
138 1 : nns_loge ("Got invalid meta info");
139 1 : goto done;
140 : }
141 :
142 : /** alloc maximum possible size of memory */
143 76 : values = g_malloc0 (element_size * element_count);
144 76 : indices = g_malloc0 (sizeof (guint) * element_count);
145 :
146 76 : data_type = meta->type;
147 :
148 : /** Consider using macro to reduce loc and readability */
149 24381 : for (i = 0; i < element_count; ++i) {
150 24305 : switch (data_type) {
151 40 : case _NNS_INT32:
152 40 : if (((int32_t *) map.data)[i] != 0) {
153 6 : ((int32_t *) values)[nnz] = ((int32_t *) map.data)[i];
154 6 : indices[nnz] = i;
155 6 : nnz += 1;
156 : }
157 40 : break;
158 40 : case _NNS_UINT32:
159 40 : if (((uint32_t *) map.data)[i] != 0) {
160 6 : ((uint32_t *) values)[nnz] = ((uint32_t *) map.data)[i];
161 6 : indices[nnz] = i;
162 6 : nnz += 1;
163 : }
164 40 : break;
165 40 : case _NNS_INT16:
166 40 : if (((int16_t *) map.data)[i] != 0) {
167 6 : ((int16_t *) values)[nnz] = ((int16_t *) map.data)[i];
168 6 : indices[nnz] = i;
169 6 : nnz += 1;
170 : }
171 40 : break;
172 40 : case _NNS_UINT16:
173 40 : if (((uint16_t *) map.data)[i] != 0) {
174 6 : ((uint16_t *) values)[nnz] = ((uint16_t *) map.data)[i];
175 6 : indices[nnz] = i;
176 6 : nnz += 1;
177 : }
178 40 : break;
179 40 : case _NNS_INT8:
180 40 : if (((int8_t *) map.data)[i] != 0) {
181 6 : ((int8_t *) values)[nnz] = ((int8_t *) map.data)[i];
182 6 : indices[nnz] = i;
183 6 : nnz += 1;
184 : }
185 40 : break;
186 100 : case _NNS_UINT8:
187 100 : if (((uint8_t *) map.data)[i] != 0) {
188 23 : ((uint8_t *) values)[nnz] = ((uint8_t *) map.data)[i];
189 23 : indices[nnz] = i;
190 23 : nnz += 1;
191 : }
192 100 : break;
193 40 : case _NNS_FLOAT64:
194 40 : if (((double *) map.data)[i] != 0) {
195 6 : ((double *) values)[nnz] = ((double *) map.data)[i];
196 6 : indices[nnz] = i;
197 6 : nnz += 1;
198 : }
199 40 : break;
200 23885 : case _NNS_FLOAT32:
201 23885 : if (((float *) map.data)[i] != 0) {
202 4175 : ((float *) values)[nnz] = ((float *) map.data)[i];
203 4175 : indices[nnz] = i;
204 4175 : nnz += 1;
205 : }
206 23885 : break;
207 40 : case _NNS_INT64:
208 40 : if (((int64_t *) map.data)[i] != 0) {
209 6 : ((int64_t *) values)[nnz] = ((int64_t *) map.data)[i];
210 6 : indices[nnz] = i;
211 6 : nnz += 1;
212 : }
213 40 : break;
214 40 : case _NNS_UINT64:
215 40 : if (((uint64_t *) map.data)[i] != 0) {
216 6 : ((uint64_t *) values)[nnz] = ((uint64_t *) map.data)[i];
217 6 : indices[nnz] = i;
218 6 : nnz += 1;
219 : }
220 40 : break;
221 0 : default:
222 0 : nns_loge ("Error occurred during get tensor value");
223 0 : g_free (values);
224 0 : g_free (indices);
225 0 : goto done;
226 : }
227 : }
228 :
229 : /** update meta nnz info */
230 76 : meta->format = _NNS_TENSOR_FORMAT_SPARSE;
231 76 : meta->sparse_info.nnz = nnz;
232 :
233 : /** write to output buffer */
234 76 : output_size = element_size * nnz + sizeof (guint) * nnz;
235 :
236 : /** add meta info header */
237 76 : output_size += header_size;
238 76 : output = g_malloc0 (output_size);
239 :
240 76 : gst_tensor_meta_info_update_header (meta, output);
241 :
242 76 : memcpy (output + header_size, values, element_size * nnz);
243 76 : memcpy (output + header_size + (element_size * nnz),
244 : indices, sizeof (guint) * nnz);
245 :
246 76 : g_free (values);
247 76 : g_free (indices);
248 :
249 76 : sparse = gst_memory_new_wrapped (0, output, output_size, 0, output_size,
250 : output, g_free);
251 :
252 77 : done:
253 77 : gst_memory_unmap (mem, &map);
254 77 : return sparse;
255 : }
|