Coverage Report

Created: 2025-02-24 17:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/home/liu/actions-runner/_work/ccv/ccv/test/unit/nnc/tensor.tests.c
Line
Count
Source
1
#include "ccv.h"
2
#include "case.h"
3
#include "ccv_case.h"
4
#include "ccv_nnc_case.h"
5
#include "nnc/ccv_nnc.h"
6
#include "nnc/ccv_nnc_easy.h"
7
#include "3rdparty/sqlite3/sqlite3.h"
8
#include "3rdparty/dsfmt/dSFMT.h"
9
10
TEST_SETUP()
11
{
12
  ccv_nnc_init();
13
}
14
15
TEST_CASE("zero out a tensor")
16
1
{
17
1
  const ccv_nnc_tensor_param_t params = {
18
1
    .type = CCV_TENSOR_CPU_MEMORY,
19
1
    .format = CCV_TENSOR_FORMAT_NHWC,
20
1
    .datatype = CCV_32F,
21
1
    .dim = {
22
1
      10, 20, 30, 4, 5, 6,
23
1
    },
24
1
  };
25
1
  ccv_nnc_tensor_t* tensor = ccv_nnc_tensor_new(0, params, 0);
26
1
  int i;
27
720k
  for (i = 0; i < 10 * 20 * 30 * 4 * 5 * 6; 
i++720k
)
28
720k
    tensor->data.f32[i] = 1;
29
1
  ccv_nnc_tensor_zero(tensor);
30
720k
  for (i = 0; i < 10 * 20 * 30 * 4 * 5 * 6; 
i++720k
)
31
720k
    REQUIRE_EQ(0, tensor->data.f32[i], "should be zero'ed at %d", i);
32
1
  ccv_nnc_tensor_free(tensor);
33
1
}
34
35
TEST_CASE("zero out a tensor view")
36
1
{
37
1
  const ccv_nnc_tensor_param_t params = {
38
1
    .type = CCV_TENSOR_CPU_MEMORY,
39
1
    .format = CCV_TENSOR_FORMAT_NHWC,
40
1
    .datatype = CCV_32F,
41
1
    .dim = {
42
1
      10, 20, 30, 4, 5, 6,
43
1
    },
44
1
  };
45
1
  ccv_nnc_tensor_t* a_tensor = ccv_nnc_tensor_new(0, params, 0);
46
1
  int c;
47
720k
  for (c = 0; c < 10 * 20 * 30 * 4 * 5 * 6; 
c++720k
)
48
720k
    a_tensor->data.f32[c] = 1;
49
1
  int ofs[CCV_NNC_MAX_DIM_ALLOC] = {
50
1
    1, 2, 5, 1, 1, 1,
51
1
  };
52
1
  const ccv_nnc_tensor_param_t new_params = {
53
1
    .type = CCV_TENSOR_CPU_MEMORY,
54
1
    .format = CCV_TENSOR_FORMAT_NHWC,
55
1
    .datatype = CCV_32F,
56
1
    .dim = {
57
1
      8, 12, 15, 2, 3, 4,
58
1
    },
59
1
  };
60
1
  ccv_nnc_tensor_view_t a_tensor_view = ccv_nnc_tensor_view(a_tensor, new_params, ofs, DIM_ALLOC(20 * 30 * 4 * 5 * 6, 30 * 4 * 5 * 6, 4 * 5 * 6, 5 * 6, 6, 1));
61
1
  ccv_nnc_tensor_zero(&a_tensor_view);
62
1
  ccv_nnc_tensor_t* b_tensor = ccv_nnc_tensor_new(0, params, 0);
63
720k
  for (c = 0; c < 10 * 20 * 30 * 4 * 5 * 6; 
c++720k
)
64
720k
    b_tensor->data.f32[c] = 1;
65
1
  ccv_nnc_tensor_view_t b_tensor_view = ccv_nnc_tensor_view(b_tensor, new_params, ofs, DIM_ALLOC(20 * 30 * 4 * 5 * 6, 30 * 4 * 5 * 6, 4 * 5 * 6, 5 * 6, 6, 1));
66
1
  int i[6];
67
1
  float* tvp[6];
68
1
  tvp[5] = b_tensor_view.data.f32;
69
9
  for (i[5] = 0; i[5] < b_tensor_view.info.dim[0]; 
i[5]++8
)
70
8
  {
71
8
    tvp[4] = tvp[5];
72
104
    for (i[4] = 0; i[4] < b_tensor_view.info.dim[1]; 
i[4]++96
)
73
96
    {
74
96
      tvp[3] = tvp[4];
75
1.53k
      for (i[3] = 0; i[3] < b_tensor_view.info.dim[2]; 
i[3]++1.44k
)
76
1.44k
      {
77
1.44k
        tvp[2] = tvp[3];
78
4.32k
        for (i[2] = 0; i[2] < b_tensor_view.info.dim[3]; 
i[2]++2.88k
)
79
2.88k
        {
80
2.88k
          tvp[1] = tvp[2];
81
11.5k
          for (i[1] = 0; i[1] < b_tensor_view.info.dim[4]; 
i[1]++8.64k
)
82
8.64k
          {
83
8.64k
            tvp[0] = tvp[1];
84
43.2k
            for (i[0] = 0; i[0] < b_tensor_view.info.dim[5]; 
i[0]++34.5k
)
85
34.5k
            {
86
34.5k
              tvp[0][i[0]] = 0;
87
34.5k
            }
88
8.64k
            tvp[1] += b_tensor_view.stride[4];
89
8.64k
          }
90
2.88k
          tvp[2] += b_tensor_view.stride[3];
91
2.88k
        }
92
1.44k
        tvp[3] += b_tensor_view.stride[2];
93
1.44k
      }
94
96
      tvp[4] += b_tensor_view.stride[1];
95
96
    }
96
8
    tvp[5] += b_tensor_view.stride[0];
97
8
  }
98
1
  REQUIRE_TENSOR_EQ(a_tensor, b_tensor, "zero'ed tensor view should be equal");
99
1
  ccv_nnc_tensor_free(a_tensor);
100
1
  ccv_nnc_tensor_free(b_tensor);
101
1
}
102
103
TEST_CASE("hint tensor")
104
1
{
105
1
  ccv_nnc_tensor_param_t a = CPU_TENSOR_NHWC(32F, 234, 128, 3);
106
1
  ccv_nnc_hint_t hint = {
107
1
    .border = {
108
1
      .begin = {1, 1},
109
1
      .end = {1, 2}
110
1
    },
111
1
    .stride = {
112
1
      .dim = {8, 7}
113
1
    }
114
1
  };
115
1
  ccv_nnc_cmd_t cmd = CMD_CONVOLUTION_FORWARD(1, 128, 4, 5, 3);
116
1
  ccv_nnc_tensor_param_t b;
117
1
  ccv_nnc_tensor_param_t w = CPU_TENSOR_NHWC(32F, 128, 4, 5, 3);
118
1
  ccv_nnc_tensor_param_t bias = CPU_TENSOR_NHWC(32F, 128);
119
1
  ccv_nnc_hint_tensor_auto(cmd, TENSOR_PARAM_LIST(a, w, bias), hint, &b, 1);
120
1
  REQUIRE_EQ(b.dim[0], 30, "height should be 30");
121
1
  REQUIRE_EQ(b.dim[1], 19, "width should be 19");
122
1
  REQUIRE_EQ(b.dim[2], 128, "channel should be the convolution filter count");
123
1
}
124
125
TEST_CASE("tensor mapped from file")
126
1
{
127
1
  FILE* w = fopen("data/tensor.bin", "w+");
128
1
  float* w_a = (float*)ccmalloc(sizeof(float) * 4096 * 5);
129
1
  int i;
130
20.4k
  for (i = 0; i < 4096 * 5; 
i++20.4k
)
131
20.4k
    w_a[i] = (float)(i + 1);
132
1
  fwrite(w_a, 1, sizeof(float) * 4096 * 5, w);
133
1
  fclose(w);
134
1
  ccfree(w_a);
135
1
  float a[] = {1, 2, 3, 4, 5};
136
1
  ccv_nnc_tensor_t* tensor_a = ccv_nnc_tensor_new_from_file(CPU_TENSOR_NHWC(32F, 5), "data/tensor.bin", 0, 0);
137
1
  REQUIRE_ARRAY_EQ_WITH_TOLERANCE(float, tensor_a->data.f32, a, 5, 1e-5, "the first 5 element should be equal");
138
1
  float b[] = {4096 * 4 + 1, 4096 * 4 + 2, 4096 * 4 + 3, 4096 * 4 + 4};
139
1
  ccv_nnc_tensor_t* tensor_b = ccv_nnc_tensor_new_from_file(CPU_TENSOR_NHWC(32F, 4), "data/tensor.bin", (4096 * 4 * 4), 0);
140
1
  REQUIRE_ARRAY_EQ_WITH_TOLERANCE(float, tensor_b->data.f32, b, 4, 1e-5, "the first 4 element should be equal");
141
1
  ccv_nnc_tensor_free(tensor_a);
142
1
  ccv_nnc_tensor_free(tensor_b);
143
1
}
144
145
TEST_CASE("tensor persistence")
146
1
{
147
1
  sqlite3* handle;
148
1
  sqlite3_open("tensors.sqlite3", &handle);
149
1
  ccv_nnc_tensor_t* const tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 10, 20, 30), 0);
150
1
  int i;
151
1
  dsfmt_t dsfmt;
152
1
  dsfmt_init_gen_rand(&dsfmt, 1);
153
6.00k
  for (i = 0; i < 10 * 20 * 30; 
i++6.00k
)
154
6.00k
    tensor->data.f32[i] = dsfmt_genrand_open_close(&dsfmt) * 2 - 1;
155
1
  ccv_nnc_tensor_write(tensor, handle, "x", 0);
156
1
  sqlite3_close(handle);
157
1
  handle = 0;
158
1
  sqlite3_open("tensors.sqlite3", &handle);
159
1
  ccv_nnc_tensor_t* tensor1 = 0;
160
1
  ccv_nnc_tensor_read(handle, "x", 0, 0, 0, &tensor1);
161
1
  ccv_nnc_tensor_t* tensor2 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 10), 0);
162
1
  ccv_nnc_tensor_read(handle, "x", 0, 0, 0, &tensor2);
163
1
  sqlite3_close(handle);
164
1
  REQUIRE_TENSOR_EQ(tensor1, tensor, "the first tensor should equal to the second");
165
1
  REQUIRE_ARRAY_EQ_WITH_TOLERANCE(float, tensor2->data.f32, tensor->data.f32, 10, 1e-5, "the first 10 element should be equal");
166
1
  REQUIRE(ccv_nnc_tensor_nd(tensor2->info.dim) == 1, "should be 1-d tensor");
167
1
  REQUIRE_EQ(tensor2->info.dim[0], 10, "should be 1-d tensor with 10-element");
168
1
  ccv_nnc_tensor_free(tensor1);
169
1
  ccv_nnc_tensor_free(tensor2);
170
1
  ccv_nnc_tensor_free(tensor);
171
1
}
172
173
static int _tensor_xor_encode(const void* const data, const size_t data_size, const int datatype, const int* const dimensions, const int dimension_count, void* const context, void* const encoded, size_t* const encoded_size, ccv_nnc_tensor_param_t* const params, unsigned int* const identifier)
174
6
{
175
6
  unsigned char* const u8 = (unsigned char*)data;
176
6
  unsigned char* const u8enc = (unsigned char*)encoded;
177
6
  int i;
178
120k
  for (i = 0; i < data_size; 
i++120k
)
179
120k
    u8enc[i] = u8[i] ^ 0x13;
180
6
  *encoded_size = data_size;
181
6
  *identifier = 1;
182
6
  return 1;
183
6
}
184
185
static int _tensor_xor_decode(const void* const data, const size_t data_size, const int datatype, const int* const dimensions, const int dimension_count, const unsigned int identifier, void* const context, const ccv_nnc_tensor_param_t tensor_params, ccv_nnc_tensor_t** const tensor_out, void* decoded, size_t* const decoded_size)
186
8
{
187
8
  if (identifier != 1)
188
0
    return 0;
189
8
  if (!tensor_out[0])
190
2
  {
191
2
    tensor_out[0] = ccv_nnc_tensor_new(0, tensor_params, 0);
192
2
    if (!decoded)
193
1
      decoded = tensor_out[0]->data.u8;
194
2
  }
195
8
  unsigned char* const u8 = (unsigned char*)data;
196
8
  unsigned char* const u8dec = (unsigned char*)decoded;
197
8
  const size_t expected_size = *decoded_size;
198
8
  int i;
199
48.5k
  for (i = 0; i < ccv_min(expected_size, data_size); 
i++48.5k
)
200
48.5k
    u8dec[i] = u8[i] ^ 0x13;
201
8
  *decoded_size = ccv_min(expected_size, data_size);
202
8
  return 1;
203
8
}
204
205
static int _tensor_noop_encode(const void* const data, const size_t data_size, const int datatype, const int* const dimensions, const int dimension_count, void* const context, void* const encoded, size_t* const encoded_size, ccv_nnc_tensor_param_t* const params, unsigned int* const identifier)
206
6
{
207
6
  return 0;
208
6
}
209
210
static int _tensor_noop_decode(const void* const data, const size_t data_size, const int datatype, const int* const dimensions, const int dimension_count, const unsigned int identifier, void* const context, const ccv_nnc_tensor_param_t tensor_params, ccv_nnc_tensor_t** const tensor_out, void* const decoded, size_t* const decoded_size)
211
8
{
212
8
  return 0;
213
8
}
214
215
TEST_CASE("tensor persistence with encoder / decoder")
216
1
{
217
1
  sqlite3* handle;
218
1
  sqlite3_open("tensors_de.sqlite3", &handle);
219
1
  ccv_nnc_tensor_t* const tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 10, 20, 30), 0);
220
1
  int i;
221
1
  dsfmt_t dsfmt;
222
1
  dsfmt_init_gen_rand(&dsfmt, 1);
223
6.00k
  for (i = 0; i < 10 * 20 * 30; 
i++6.00k
)
224
6.00k
    tensor->data.f32[i] = dsfmt_genrand_open_close(&dsfmt) * 2 - 1;
225
1
  ccv_nnc_tensor_io_option_t options = {
226
1
    .encode = _tensor_xor_encode,
227
1
    .decode = _tensor_xor_decode
228
1
  };
229
1
  ccv_nnc_tensor_write(tensor, handle, "y", &options);
230
1
  sqlite3_close(handle);
231
1
  handle = 0;
232
1
  sqlite3_open("tensors_de.sqlite3", &handle);
233
1
  ccv_nnc_tensor_t* tensor1 = 0;
234
1
  ccv_nnc_tensor_read(handle, "y", &options, 0, 0, &tensor1);
235
1
  ccv_nnc_tensor_t* tensor2 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 10), 0);
236
1
  ccv_nnc_tensor_read(handle, "y", &options, 0, 0, &tensor2);
237
1
  sqlite3_close(handle);
238
1
  REQUIRE_TENSOR_EQ(tensor1, tensor, "the first tensor should equal to the second");
239
1
  REQUIRE_ARRAY_EQ_WITH_TOLERANCE(float, tensor2->data.f32, tensor->data.f32, 10, 1e-5, "the first 10 element should be equal");
240
1
  REQUIRE(ccv_nnc_tensor_nd(tensor2->info.dim) == 1, "should be 1-d tensor");
241
1
  REQUIRE_EQ(tensor2->info.dim[0], 10, "should be 1-d tensor with 10-element");
242
1
  ccv_nnc_tensor_free(tensor1);
243
1
  ccv_nnc_tensor_free(tensor2);
244
1
  ccv_nnc_tensor_free(tensor);
245
1
}
246
247
TEST_CASE("tensor persistence with noop encoder / decoder")
248
1
{
249
1
  sqlite3* handle;
250
1
  sqlite3_open("tensors_noop_de.sqlite3", &handle);
251
1
  ccv_nnc_tensor_t* const tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 10, 20, 30), 0);
252
1
  int i;
253
1
  dsfmt_t dsfmt;
254
1
  dsfmt_init_gen_rand(&dsfmt, 1);
255
6.00k
  for (i = 0; i < 10 * 20 * 30; 
i++6.00k
)
256
6.00k
    tensor->data.f32[i] = dsfmt_genrand_open_close(&dsfmt) * 2 - 1;
257
1
  ccv_nnc_tensor_io_option_t options = {
258
1
    .encode = _tensor_noop_encode,
259
1
    .decode = _tensor_noop_decode
260
1
  };
261
1
  ccv_nnc_tensor_write(tensor, handle, "y", &options);
262
1
  sqlite3_close(handle);
263
1
  handle = 0;
264
1
  sqlite3_open("tensors_noop_de.sqlite3", &handle);
265
1
  ccv_nnc_tensor_t* tensor1 = 0;
266
1
  ccv_nnc_tensor_read(handle, "y", &options, 0, 0, &tensor1);
267
1
  ccv_nnc_tensor_t* tensor2 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 10), 0);
268
1
  ccv_nnc_tensor_read(handle, "y", &options, 0, 0, &tensor2);
269
1
  sqlite3_close(handle);
270
1
  REQUIRE_TENSOR_EQ(tensor1, tensor, "the first tensor should equal to the second");
271
1
  REQUIRE_ARRAY_EQ_WITH_TOLERANCE(float, tensor2->data.f32, tensor->data.f32, 10, 1e-5, "the first 10 element should be equal");
272
1
  REQUIRE(ccv_nnc_tensor_nd(tensor2->info.dim) == 1, "should be 1-d tensor");
273
1
  REQUIRE_EQ(tensor2->info.dim[0], 10, "should be 1-d tensor with 10-element");
274
1
  ccv_nnc_tensor_free(tensor1);
275
1
  ccv_nnc_tensor_free(tensor2);
276
1
  ccv_nnc_tensor_free(tensor);
277
1
}
278
279
TEST_CASE("tensor persistence and read metadata only")
280
1
{
281
1
  sqlite3* handle;
282
1
  sqlite3_open("tensors_md.sqlite3", &handle);
283
1
  ccv_nnc_tensor_t* const tensorf32 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 10, 20, 30), 0);
284
1
  int i;
285
1
  dsfmt_t dsfmt;
286
1
  dsfmt_init_gen_rand(&dsfmt, 1);
287
6.00k
  for (i = 0; i < 10 * 20 * 30; 
i++6.00k
)
288
6.00k
    tensorf32->data.f32[i] = dsfmt_genrand_open_close(&dsfmt) * 2 - 1;
289
1
  ccv_nnc_tensor_t* const tensorf16 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(16F, 10, 20, 30), 0);
290
1
  ccv_float_to_half_precision(tensorf32->data.f32, (uint16_t*)tensorf16->data.f16, 10 * 20 * 30);
291
6.00k
  for (i = 0; i < 10 * 20 * 30; 
i++6.00k
)
292
6.00k
    tensorf32->data.f32[i] = dsfmt_genrand_open_close(&dsfmt) * 2 - 1;
293
1
  ccv_nnc_tensor_write(tensorf16, handle, "x", 0);
294
1
  ccv_nnc_tensor_write(tensorf32, handle, "y", 0);
295
1
  sqlite3_close(handle);
296
1
  handle = 0;
297
1
  sqlite3_open("tensors_md.sqlite3", &handle);
298
1
  ccv_nnc_tensor_t* tensor1 = 0;
299
1
  ccv_nnc_tensor_read(handle, "x", 0, CCV_NNC_TENSOR_READ_METADATA_ONLY, 0, &tensor1);
300
1
  ccv_nnc_tensor_t* tensor2 = 0;
301
1
  ccv_nnc_tensor_read(handle, "y", 0, CCV_NNC_TENSOR_READ_METADATA_ONLY, 0, &tensor2);
302
1
  sqlite3_close(handle);
303
1
  REQUIRE(tensor1->data.u8 == 0, "should have no data");
304
1
  REQUIRE(tensor2->data.u8 == 0, "should have no data");
305
1
  REQUIRE_EQ(tensor1->info.dim[0], 10, "should be 3-d tensor with 10, 20, 30");
306
1
  REQUIRE_EQ(tensor2->info.dim[0], 10, "should be 3-d tensor with 10, 20, 30");
307
1
  REQUIRE_EQ(tensor1->info.dim[1], 20, "should be 3-d tensor with 10, 20, 30");
308
1
  REQUIRE_EQ(tensor2->info.dim[1], 20, "should be 3-d tensor with 10, 20, 30");
309
1
  REQUIRE_EQ(tensor1->info.dim[2], 30, "should be 3-d tensor with 10, 20, 30");
310
1
  REQUIRE_EQ(tensor2->info.dim[2], 30, "should be 3-d tensor with 10, 20, 30");
311
1
  REQUIRE_EQ(tensor1->info.dim[3], 0, "should be 3-d tensor with 10, 20, 30");
312
1
  REQUIRE_EQ(tensor2->info.dim[3], 0, "should be 3-d tensor with 10, 20, 30");
313
1
  ccv_nnc_tensor_free(tensor1);
314
1
  ccv_nnc_tensor_free(tensor2);
315
1
  ccv_nnc_tensor_free(tensorf16);
316
1
  ccv_nnc_tensor_free(tensorf32);
317
1
}
318
319
TEST_CASE("tensor persistence with type coercion")
320
1
{
321
1
  sqlite3* handle;
322
1
  sqlite3_open("tensors_tc.sqlite3", &handle);
323
1
  ccv_nnc_tensor_t* const tensorf32 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 10, 20, 30), 0);
324
1
  int i;
325
1
  dsfmt_t dsfmt;
326
1
  dsfmt_init_gen_rand(&dsfmt, 1);
327
6.00k
  for (i = 0; i < 10 * 20 * 30; 
i++6.00k
)
328
6.00k
    tensorf32->data.f32[i] = dsfmt_genrand_open_close(&dsfmt) * 2 - 1;
329
1
  ccv_nnc_tensor_t* const tensorf16 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(16F, 10, 20, 30), 0);
330
1
  ccv_float_to_half_precision(tensorf32->data.f32, (uint16_t*)tensorf16->data.f16, 10 * 20 * 30);
331
6.00k
  for (i = 0; i < 10 * 20 * 30; 
i++6.00k
)
332
6.00k
    tensorf32->data.f32[i] = dsfmt_genrand_open_close(&dsfmt) * 2 - 1;
333
1
  ccv_nnc_tensor_write(tensorf16, handle, "x", 0);
334
1
  ccv_nnc_tensor_write(tensorf32, handle, "y", 0);
335
1
  sqlite3_close(handle);
336
1
  handle = 0;
337
1
  sqlite3_open("tensors_tc.sqlite3", &handle);
338
1
  ccv_nnc_tensor_t* tensor1 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 10), 0);
339
1
  ccv_nnc_tensor_read(handle, "x", 0, 0, 0, &tensor1);
340
1
  ccv_nnc_tensor_t* tensor2 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(16F, 10), 0);
341
1
  ccv_nnc_tensor_read(handle, "y", 0, 0, 0, &tensor2);
342
1
  sqlite3_close(handle);
343
1
  float* tensor1_ref = (float*)ccmalloc(sizeof(float) * 10);
344
1
  ccv_half_precision_to_float((uint16_t*)tensorf16->data.f16, tensor1_ref, 10);
345
1
  float* tensor2_ret = (float*)ccmalloc(sizeof(float) * 10);
346
1
  ccv_half_precision_to_float((uint16_t*)tensor2->data.f16, tensor2_ret, 10);
347
1
  REQUIRE_ARRAY_EQ_WITH_TOLERANCE(float, tensor1->data.f32, tensor1_ref, 10, 1e-3, "the first 10 element should be equal");
348
1
  REQUIRE_ARRAY_EQ_WITH_TOLERANCE(float, tensor2_ret, tensorf32->data.f32, 10, 1e-3, "the first 10 element should be equal");
349
1
  REQUIRE(ccv_nnc_tensor_nd(tensor1->info.dim) == 1, "should be 1-d tensor");
350
1
  REQUIRE(ccv_nnc_tensor_nd(tensor2->info.dim) == 1, "should be 1-d tensor");
351
1
  REQUIRE_EQ(tensor1->info.dim[0], 10, "should be 1-d tensor with 10-element");
352
1
  REQUIRE_EQ(tensor2->info.dim[0], 10, "should be 1-d tensor with 10-element");
353
1
  ccv_nnc_tensor_free(tensor1);
354
1
  ccv_nnc_tensor_free(tensor2);
355
1
  ccv_nnc_tensor_free(tensorf16);
356
1
  ccv_nnc_tensor_free(tensorf32);
357
1
  ccfree(tensor1_ref);
358
1
  ccfree(tensor2_ret);
359
1
}
360
361
TEST_CASE("tensor persistence with type coercion and encoder / decoder")
362
1
{
363
1
  sqlite3* handle;
364
1
  sqlite3_open("tensors_tc_de.sqlite3", &handle);
365
1
  ccv_nnc_tensor_t* const tensorf32 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 10, 20, 30), 0);
366
1
  int i;
367
1
  dsfmt_t dsfmt;
368
1
  dsfmt_init_gen_rand(&dsfmt, 1);
369
6.00k
  for (i = 0; i < 10 * 20 * 30; 
i++6.00k
)
370
6.00k
    tensorf32->data.f32[i] = dsfmt_genrand_open_close(&dsfmt) * 2 - 1;
371
1
  ccv_nnc_tensor_t* const tensorf16 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(16F, 10, 20, 30), 0);
372
1
  ccv_float_to_half_precision(tensorf32->data.f32, (uint16_t*)tensorf16->data.f16, 10 * 20 * 30);
373
6.00k
  for (i = 0; i < 10 * 20 * 30; 
i++6.00k
)
374
6.00k
    tensorf32->data.f32[i] = dsfmt_genrand_open_close(&dsfmt) * 2 - 1;
375
1
  ccv_nnc_tensor_io_option_t options = {
376
1
    .encode = _tensor_xor_encode,
377
1
    .decode = _tensor_xor_decode
378
1
  };
379
1
  ccv_nnc_tensor_write(tensorf16, handle, "x", &options);
380
1
  ccv_nnc_tensor_write(tensorf32, handle, "y", &options);
381
1
  sqlite3_close(handle);
382
1
  handle = 0;
383
1
  sqlite3_open("tensors_tc_de.sqlite3", &handle);
384
1
  ccv_nnc_tensor_t* tensor1 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 10), 0);
385
1
  ccv_nnc_tensor_read(handle, "x", &options, 0, 0, &tensor1);
386
1
  ccv_nnc_tensor_t* tensor2 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(16F, 10), 0);
387
1
  ccv_nnc_tensor_read(handle, "y", &options, 0, 0, &tensor2);
388
1
  sqlite3_close(handle);
389
1
  float* tensor1_ref = (float*)ccmalloc(sizeof(float) * 10);
390
1
  ccv_half_precision_to_float((uint16_t*)tensorf16->data.f16, tensor1_ref, 10);
391
1
  float* tensor2_ret = (float*)ccmalloc(sizeof(float) * 10);
392
1
  ccv_half_precision_to_float((uint16_t*)tensor2->data.f16, tensor2_ret, 10);
393
1
  REQUIRE_ARRAY_EQ_WITH_TOLERANCE(float, tensor1->data.f32, tensor1_ref, 10, 1e-3, "the first 10 element should be equal");
394
1
  REQUIRE_ARRAY_EQ_WITH_TOLERANCE(float, tensor2_ret, tensorf32->data.f32, 10, 1e-3, "the first 10 element should be equal");
395
1
  REQUIRE(ccv_nnc_tensor_nd(tensor1->info.dim) == 1, "should be 1-d tensor");
396
1
  REQUIRE(ccv_nnc_tensor_nd(tensor2->info.dim) == 1, "should be 1-d tensor");
397
1
  REQUIRE_EQ(tensor1->info.dim[0], 10, "should be 1-d tensor with 10-element");
398
1
  REQUIRE_EQ(tensor2->info.dim[0], 10, "should be 1-d tensor with 10-element");
399
1
  ccv_nnc_tensor_free(tensor1);
400
1
  ccv_nnc_tensor_free(tensor2);
401
1
  ccv_nnc_tensor_free(tensorf16);
402
1
  ccv_nnc_tensor_free(tensorf32);
403
1
  ccfree(tensor1_ref);
404
1
  ccfree(tensor2_ret);
405
1
}
406
407
TEST_CASE("tensor persistence with type coercion and noop encoder / decoder")
408
1
{
409
1
  sqlite3* handle;
410
1
  sqlite3_open("tensors_tc_noop_de.sqlite3", &handle);
411
1
  ccv_nnc_tensor_t* const tensorf32 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 10, 20, 30), 0);
412
1
  int i;
413
1
  dsfmt_t dsfmt;
414
1
  dsfmt_init_gen_rand(&dsfmt, 1);
415
6.00k
  for (i = 0; i < 10 * 20 * 30; 
i++6.00k
)
416
6.00k
    tensorf32->data.f32[i] = dsfmt_genrand_open_close(&dsfmt) * 2 - 1;
417
1
  ccv_nnc_tensor_t* const tensorf16 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(16F, 10, 20, 30), 0);
418
1
  ccv_float_to_half_precision(tensorf32->data.f32, (uint16_t*)tensorf16->data.f16, 10 * 20 * 30);
419
6.00k
  for (i = 0; i < 10 * 20 * 30; 
i++6.00k
)
420
6.00k
    tensorf32->data.f32[i] = dsfmt_genrand_open_close(&dsfmt) * 2 - 1;
421
1
  ccv_nnc_tensor_io_option_t options = {
422
1
    .encode = _tensor_noop_encode,
423
1
    .decode = _tensor_noop_decode
424
1
  };
425
1
  ccv_nnc_tensor_write(tensorf16, handle, "x", &options);
426
1
  ccv_nnc_tensor_write(tensorf32, handle, "y", &options);
427
1
  sqlite3_close(handle);
428
1
  handle = 0;
429
1
  sqlite3_open("tensors_tc_noop_de.sqlite3", &handle);
430
1
  ccv_nnc_tensor_t* tensor1 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 10), 0);
431
1
  ccv_nnc_tensor_read(handle, "x", &options, 0, 0, &tensor1);
432
1
  ccv_nnc_tensor_t* tensor2 = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(16F, 10), 0);
433
1
  ccv_nnc_tensor_read(handle, "y", &options, 0, 0, &tensor2);
434
1
  sqlite3_close(handle);
435
1
  float* tensor1_ref = (float*)ccmalloc(sizeof(float) * 10);
436
1
  ccv_half_precision_to_float((uint16_t*)tensorf16->data.f16, tensor1_ref, 10);
437
1
  float* tensor2_ret = (float*)ccmalloc(sizeof(float) * 10);
438
1
  ccv_half_precision_to_float((uint16_t*)tensor2->data.f16, tensor2_ret, 10);
439
1
  REQUIRE_ARRAY_EQ_WITH_TOLERANCE(float, tensor1->data.f32, tensor1_ref, 10, 1e-3, "the first 10 element should be equal");
440
1
  REQUIRE_ARRAY_EQ_WITH_TOLERANCE(float, tensor2_ret, tensorf32->data.f32, 10, 1e-3, "the first 10 element should be equal");
441
1
  REQUIRE(ccv_nnc_tensor_nd(tensor1->info.dim) == 1, "should be 1-d tensor");
442
1
  REQUIRE(ccv_nnc_tensor_nd(tensor2->info.dim) == 1, "should be 1-d tensor");
443
1
  REQUIRE_EQ(tensor1->info.dim[0], 10, "should be 1-d tensor with 10-element");
444
1
  REQUIRE_EQ(tensor2->info.dim[0], 10, "should be 1-d tensor with 10-element");
445
1
  ccv_nnc_tensor_free(tensor1);
446
1
  ccv_nnc_tensor_free(tensor2);
447
1
  ccv_nnc_tensor_free(tensorf16);
448
1
  ccv_nnc_tensor_free(tensorf32);
449
1
  ccfree(tensor1_ref);
450
1
  ccfree(tensor2_ret);
451
1
}
452
453
TEST_CASE("resize tensor")
454
1
{
455
1
  ccv_nnc_tensor_t* tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 12, 12, 3), 0);
456
1
  int i;
457
433
  for (i = 0; i < 12 * 12 * 3; 
i++432
)
458
432
    tensor->data.f32[i] = i;
459
1
  tensor = ccv_nnc_tensor_resize(tensor, CPU_TENSOR_NHWC(32F, 23, 23, 3));
460
1.15k
  for (i = 12 * 12 * 3; i < 23 * 23 * 3; 
i++1.15k
)
461
1.15k
    tensor->data.f32[i] = i;
462
1
  ccv_nnc_tensor_t* b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 23, 23, 3), 0);
463
1.58k
  for (i = 0; i < 23 * 23 * 3; 
i++1.58k
)
464
1.58k
    b->data.f32[i] = i;
465
1
  REQUIRE_TENSOR_EQ(tensor, b, "should retain the content when resize a tensor");
466
1
  ccv_nnc_tensor_free(tensor);
467
1
  ccv_nnc_tensor_free(b);
468
1
}
469
470
TEST_CASE("format 5-d tensor into string")
471
1
{
472
1
  ccv_nnc_tensor_t* tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32S, 2, 5, 2, 9, 9), 0);
473
1
  int i;
474
1.62k
  for (i = 0; i < 81 * 2 * 5 * 2; 
i++1.62k
)
475
1.62k
    tensor->data.i32[i] = i;
476
1
  char* str = ccv_nnc_tensor_format_new(tensor);
477
1
  const char t[] = "[\n"
478
1
"  [[[[         0,          1,          2,  ...,          6,          7,          8],\n"
479
1
"     [         9,         10,         11,  ...,         15,         16,         17],\n"
480
1
"     [        18,         19,         20,  ...,         24,         25,         26],\n"
481
1
"     ...,\n"
482
1
"     [        54,         55,         56,  ...,         60,         61,         62],\n"
483
1
"     [        63,         64,         65,  ...,         69,         70,         71],\n"
484
1
"     [        72,         73,         74,  ...,         78,         79,         80]],\n"
485
1
"    [[        81,         82,         83,  ...,         87,         88,         89],\n"
486
1
"     [        90,         91,         92,  ...,         96,         97,         98],\n"
487
1
"     [        99,        100,        101,  ...,        105,        106,        107],\n"
488
1
"     ...,\n"
489
1
"     [       135,        136,        137,  ...,        141,        142,        143],\n"
490
1
"     [       144,        145,        146,  ...,        150,        151,        152],\n"
491
1
"     [       153,        154,        155,  ...,        159,        160,        161]]],\n"
492
1
"   [[[       162,        163,        164,  ...,        168,        169,        170],\n"
493
1
"     [       171,        172,        173,  ...,        177,        178,        179],\n"
494
1
"     [       180,        181,        182,  ...,        186,        187,        188],\n"
495
1
"     ...,\n"
496
1
"     [       216,        217,        218,  ...,        222,        223,        224],\n"
497
1
"     [       225,        226,        227,  ...,        231,        232,        233],\n"
498
1
"     [       234,        235,        236,  ...,        240,        241,        242]],\n"
499
1
"    [[       243,        244,        245,  ...,        249,        250,        251],\n"
500
1
"     [       252,        253,        254,  ...,        258,        259,        260],\n"
501
1
"     [       261,        262,        263,  ...,        267,        268,        269],\n"
502
1
"     ...,\n"
503
1
"     [       297,        298,        299,  ...,        303,        304,        305],\n"
504
1
"     [       306,        307,        308,  ...,        312,        313,        314],\n"
505
1
"     [       315,        316,        317,  ...,        321,        322,        323]]],\n"
506
1
"   ...,\n"
507
1
"   [[[       486,        487,        488,  ...,        492,        493,        494],\n"
508
1
"     [       495,        496,        497,  ...,        501,        502,        503],\n"
509
1
"     [       504,        505,        506,  ...,        510,        511,        512],\n"
510
1
"     ...,\n"
511
1
"     [       540,        541,        542,  ...,        546,        547,        548],\n"
512
1
"     [       549,        550,        551,  ...,        555,        556,        557],\n"
513
1
"     [       558,        559,        560,  ...,        564,        565,        566]],\n"
514
1
"    [[       567,        568,        569,  ...,        573,        574,        575],\n"
515
1
"     [       576,        577,        578,  ...,        582,        583,        584],\n"
516
1
"     [       585,        586,        587,  ...,        591,        592,        593],\n"
517
1
"     ...,\n"
518
1
"     [       621,        622,        623,  ...,        627,        628,        629],\n"
519
1
"     [       630,        631,        632,  ...,        636,        637,        638],\n"
520
1
"     [       639,        640,        641,  ...,        645,        646,        647]]],\n"
521
1
"   [[[       648,        649,        650,  ...,        654,        655,        656],\n"
522
1
"     [       657,        658,        659,  ...,        663,        664,        665],\n"
523
1
"     [       666,        667,        668,  ...,        672,        673,        674],\n"
524
1
"     ...,\n"
525
1
"     [       702,        703,        704,  ...,        708,        709,        710],\n"
526
1
"     [       711,        712,        713,  ...,        717,        718,        719],\n"
527
1
"     [       720,        721,        722,  ...,        726,        727,        728]],\n"
528
1
"    [[       729,        730,        731,  ...,        735,        736,        737],\n"
529
1
"     [       738,        739,        740,  ...,        744,        745,        746],\n"
530
1
"     [       747,        748,        749,  ...,        753,        754,        755],\n"
531
1
"     ...,\n"
532
1
"     [       783,        784,        785,  ...,        789,        790,        791],\n"
533
1
"     [       792,        793,        794,  ...,        798,        799,        800],\n"
534
1
"     [       801,        802,        803,  ...,        807,        808,        809]]]],\n"
535
1
"  [[[[       810,        811,        812,  ...,        816,        817,        818],\n"
536
1
"     [       819,        820,        821,  ...,        825,        826,        827],\n"
537
1
"     [       828,        829,        830,  ...,        834,        835,        836],\n"
538
1
"     ...,\n"
539
1
"     [       864,        865,        866,  ...,        870,        871,        872],\n"
540
1
"     [       873,        874,        875,  ...,        879,        880,        881],\n"
541
1
"     [       882,        883,        884,  ...,        888,        889,        890]],\n"
542
1
"    [[       891,        892,        893,  ...,        897,        898,        899],\n"
543
1
"     [       900,        901,        902,  ...,        906,        907,        908],\n"
544
1
"     [       909,        910,        911,  ...,        915,        916,        917],\n"
545
1
"     ...,\n"
546
1
"     [       945,        946,        947,  ...,        951,        952,        953],\n"
547
1
"     [       954,        955,        956,  ...,        960,        961,        962],\n"
548
1
"     [       963,        964,        965,  ...,        969,        970,        971]]],\n"
549
1
"   [[[       972,        973,        974,  ...,        978,        979,        980],\n"
550
1
"     [       981,        982,        983,  ...,        987,        988,        989],\n"
551
1
"     [       990,        991,        992,  ...,        996,        997,        998],\n"
552
1
"     ...,\n"
553
1
"     [      1026,       1027,       1028,  ...,       1032,       1033,       1034],\n"
554
1
"     [      1035,       1036,       1037,  ...,       1041,       1042,       1043],\n"
555
1
"     [      1044,       1045,       1046,  ...,       1050,       1051,       1052]],\n"
556
1
"    [[      1053,       1054,       1055,  ...,       1059,       1060,       1061],\n"
557
1
"     [      1062,       1063,       1064,  ...,       1068,       1069,       1070],\n"
558
1
"     [      1071,       1072,       1073,  ...,       1077,       1078,       1079],\n"
559
1
"     ...,\n"
560
1
"     [      1107,       1108,       1109,  ...,       1113,       1114,       1115],\n"
561
1
"     [      1116,       1117,       1118,  ...,       1122,       1123,       1124],\n"
562
1
"     [      1125,       1126,       1127,  ...,       1131,       1132,       1133]]],\n"
563
1
"   ...,\n"
564
1
"   [[[      1296,       1297,       1298,  ...,       1302,       1303,       1304],\n"
565
1
"     [      1305,       1306,       1307,  ...,       1311,       1312,       1313],\n"
566
1
"     [      1314,       1315,       1316,  ...,       1320,       1321,       1322],\n"
567
1
"     ...,\n"
568
1
"     [      1350,       1351,       1352,  ...,       1356,       1357,       1358],\n"
569
1
"     [      1359,       1360,       1361,  ...,       1365,       1366,       1367],\n"
570
1
"     [      1368,       1369,       1370,  ...,       1374,       1375,       1376]],\n"
571
1
"    [[      1377,       1378,       1379,  ...,       1383,       1384,       1385],\n"
572
1
"     [      1386,       1387,       1388,  ...,       1392,       1393,       1394],\n"
573
1
"     [      1395,       1396,       1397,  ...,       1401,       1402,       1403],\n"
574
1
"     ...,\n"
575
1
"     [      1431,       1432,       1433,  ...,       1437,       1438,       1439],\n"
576
1
"     [      1440,       1441,       1442,  ...,       1446,       1447,       1448],\n"
577
1
"     [      1449,       1450,       1451,  ...,       1455,       1456,       1457]]],\n"
578
1
"   [[[      1458,       1459,       1460,  ...,       1464,       1465,       1466],\n"
579
1
"     [      1467,       1468,       1469,  ...,       1473,       1474,       1475],\n"
580
1
"     [      1476,       1477,       1478,  ...,       1482,       1483,       1484],\n"
581
1
"     ...,\n"
582
1
"     [      1512,       1513,       1514,  ...,       1518,       1519,       1520],\n"
583
1
"     [      1521,       1522,       1523,  ...,       1527,       1528,       1529],\n"
584
1
"     [      1530,       1531,       1532,  ...,       1536,       1537,       1538]],\n"
585
1
"    [[      1539,       1540,       1541,  ...,       1545,       1546,       1547],\n"
586
1
"     [      1548,       1549,       1550,  ...,       1554,       1555,       1556],\n"
587
1
"     [      1557,       1558,       1559,  ...,       1563,       1564,       1565],\n"
588
1
"     ...,\n"
589
1
"     [      1593,       1594,       1595,  ...,       1599,       1600,       1601],\n"
590
1
"     [      1602,       1603,       1604,  ...,       1608,       1609,       1610],\n"
591
1
"     [      1611,       1612,       1613,  ...,       1617,       1618,       1619]]]]\n"
592
1
"]";
593
1
  REQUIRE(memcmp(str, t, strlen(t) + 1) == 0, "output should be equal");
594
1
  ccfree(str);
595
1
  ccv_nnc_tensor_free(tensor);
596
1
}
597
598
TEST_CASE("format small 2-d tensor into string")
599
1
{
600
1
  ccv_nnc_tensor_t* tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32S, 4, 4), 0);
601
1
  int i;
602
17
  for (i = 0; i < 4 * 4; 
i++16
)
603
16
    tensor->data.i32[i] = i;
604
1
  char* str = ccv_nnc_tensor_format_new(tensor);
605
1
  const char t[] = "[\n"
606
1
"  [         0,          1,          2,          3],\n"
607
1
"  [         4,          5,          6,          7],\n"
608
1
"  [         8,          9,         10,         11],\n"
609
1
"  [        12,         13,         14,         15]\n"
610
1
"]";
611
1
  REQUIRE(memcmp(str, t, strlen(t) + 1) == 0, "output should be equal");
612
1
  ccfree(str);
613
1
  ccv_nnc_tensor_free(tensor);
614
1
}
615
616
TEST_CASE("format small 1-d tensor into string")
617
1
{
618
1
  ccv_nnc_tensor_t* tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32S, 12), 0);
619
1
  int i;
620
13
  for (i = 0; i < 12; 
i++12
)
621
12
    tensor->data.i32[i] = i;
622
1
  char* str = ccv_nnc_tensor_format_new(tensor);
623
1
  const char t[] = "[\n"
624
1
"           0,          1,          2,          3,          4,          5,          6,          7,\n"
625
1
"           8,          9,         10,         11\n"
626
1
"]";
627
1
  REQUIRE(memcmp(str, t, strlen(t) + 1) == 0, "output should be equal");
628
1
  ccfree(str);
629
1
  ccv_nnc_tensor_free(tensor);
630
1
}
631
632
TEST_CASE("format large 1-d tensor into string")
633
1
{
634
1
  ccv_nnc_tensor_t* tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32S, 68), 0);
635
1
  int i;
636
69
  for (i = 0; i < 68; 
i++68
)
637
68
    tensor->data.i32[i] = i;
638
1
  char* str = ccv_nnc_tensor_format_new(tensor);
639
1
  const char t[] = "[\n"
640
1
"           0,          1,          2,          3,          4,          5,          6,          7,\n"
641
1
"           8,          9,         10,         11,         12,         13,         14,         15,\n"
642
1
"          16,         17,         18,         19,         20,         21,         22,         23,\n"
643
1
"  ...,\n"
644
1
"          48,         49,         50,         51,         52,         53,         54,         55,\n"
645
1
"          56,         57,         58,         59,         60,         61,         62,         63,\n"
646
1
"          64,         65,         66,         67\n"
647
1
"]";
648
1
  REQUIRE(memcmp(str, t, strlen(t) + 1) == 0, "output should be equal");
649
1
  ccfree(str);
650
1
  ccv_nnc_tensor_free(tensor);
651
1
}
652
653
TEST_CASE("allocate palettize tensor with quantization to 5-bit")
654
1
{
655
1
  ccv_nnc_tensor_t* const tensor = ccv_nnc_tensor_new(0, ccv_nnc_tensor_palettize(CPU_TENSOR_NHWC(32F, 10, 20, 30), 5, 512), 0);
656
1
  REQUIRE_EQ(5312, ccv_nnc_tensor_data_size(tensor->info), "should be this size");
657
1
  ccv_nnc_tensor_free(tensor);
658
1
}
659
660
#include "case_main.h"