Coverage Report

Created: 2024-06-10 14:19

/home/liu/actions-runner/_work/ccv/ccv/test/unit/nnc/reduce.tests.c
Line
Count
Source
1
#include "case.h"
2
#include "ccv_case.h"
3
#include "ccv_nnc_case.h"
4
#include <ccv.h>
5
#include <nnc/ccv_nnc.h>
6
#include <nnc/ccv_nnc_easy.h>
7
#include "3rdparty/dsfmt/dSFMT.h"
8
9
TEST_SETUP()
10
{
11
  ccv_nnc_init();
12
}
13
14
TEST_CASE("reduce sum for [[1, 2, 3], [4, 5, 6]] on axis 1")
15
1
{
16
1
  ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
17
1
  ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 1), 0);
18
1
  a->data.f32[0] = 1;
19
1
  a->data.f32[1] = 2;
20
1
  a->data.f32[2] = 3;
21
1
  a->data.f32[3] = 4;
22
1
  a->data.f32[4] = 5;
23
1
  a->data.f32[5] = 6;
24
1
  ccv_nnc_cmd_exec(CMD_REDUCE_SUM_FORWARD(1), ccv_nnc_no_hint, 0, TENSOR_LIST(a), TENSOR_LIST(b), 0);
25
1
  float btp[] = {
26
1
    6,
27
1
    15
28
1
  };
29
1
  ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32F, 2, 1), 0);
30
1
  REQUIRE_TENSOR_EQ(b, &bt, "result should be equal");
31
1
  ccv_nnc_tensor_free(a);
32
1
  ccv_nnc_tensor_free(b);
33
1
}
34
35
TEST_CASE("reduce sum for [[1, 2, 3], [4, 5, 6]] on axis 0")
36
1
{
37
1
  ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
38
1
  ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 3), 0);
39
1
  a->data.f32[0] = 1;
40
1
  a->data.f32[1] = 2;
41
1
  a->data.f32[2] = 3;
42
1
  a->data.f32[3] = 4;
43
1
  a->data.f32[4] = 5;
44
1
  a->data.f32[5] = 6;
45
1
  ccv_nnc_cmd_exec(CMD_REDUCE_SUM_FORWARD(0), ccv_nnc_no_hint, 0, TENSOR_LIST(a), TENSOR_LIST(b), 0);
46
1
  float btp[] = {
47
1
    5, 7, 9
48
1
  };
49
1
  ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32F, 3), 0);
50
1
  REQUIRE_TENSOR_EQ(b, &bt, "result should be equal");
51
1
  ccv_nnc_tensor_free(a);
52
1
  ccv_nnc_tensor_free(b);
53
1
}
54
55
TEST_CASE("reduce mean for [[1, 2, 3], [4, 5, 6]] on axis 1")
56
1
{
57
1
  ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
58
1
  ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 1), 0);
59
1
  a->data.f32[0] = 1;
60
1
  a->data.f32[1] = 2;
61
1
  a->data.f32[2] = 3;
62
1
  a->data.f32[3] = 4;
63
1
  a->data.f32[4] = 5;
64
1
  a->data.f32[5] = 6;
65
1
  ccv_nnc_cmd_exec(CMD_REDUCE_MEAN_FORWARD(1), ccv_nnc_no_hint, 0, TENSOR_LIST(a), TENSOR_LIST(b), 0);
66
1
  float btp[] = {
67
1
    2,
68
1
    5
69
1
  };
70
1
  ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32F, 2, 1), 0);
71
1
  REQUIRE_TENSOR_EQ(b, &bt, "result should be equal");
72
1
  ccv_nnc_tensor_free(a);
73
1
  ccv_nnc_tensor_free(b);
74
1
}
75
76
TEST_CASE("reduce mean for [[1, 2, 3], [4, 5, 6]] on axis 0")
77
1
{
78
1
  ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
79
1
  ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 3), 0);
80
1
  a->data.f32[0] = 1;
81
1
  a->data.f32[1] = 2;
82
1
  a->data.f32[2] = 3;
83
1
  a->data.f32[3] = 4;
84
1
  a->data.f32[4] = 5;
85
1
  a->data.f32[5] = 6;
86
1
  ccv_nnc_cmd_exec(CMD_REDUCE_MEAN_FORWARD(0), ccv_nnc_no_hint, 0, TENSOR_LIST(a), TENSOR_LIST(b), 0);
87
1
  float btp[] = {
88
1
    2.5, 3.5, 4.5
89
1
  };
90
1
  ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32F, 3), 0);
91
1
  REQUIRE_TENSOR_EQ(b, &bt, "result should be equal");
92
1
  ccv_nnc_tensor_free(a);
93
1
  ccv_nnc_tensor_free(b);
94
1
}
95
96
TEST_CASE("use reduce for softmax")
97
1
{
98
1
  ccv_nnc_symbolic_graph_t* const symbolic_graph = ccv_nnc_symbolic_graph_new();
99
1
  ccv_nnc_tensor_symbol_t x = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 100), "x");
100
1
  ccv_nnc_tensor_symbol_t max = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "max");
101
1
  ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_REDUCE_MAX_FORWARD(0), TENSOR_SYMBOL_LIST(x), TENSOR_SYMBOL_LIST(max), "max");
102
1
  ccv_nnc_tensor_symbol_t y = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 100), "y");
103
1
  ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_ADD_FORWARD(1, -1), TENSOR_SYMBOL_LIST(x, max), TENSOR_SYMBOL_LIST(y), "neg");
104
1
  ccv_nnc_tensor_symbol_t z = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 100), "z");
105
1
  ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWEXP_FORWARD(), TENSOR_SYMBOL_LIST(y), TENSOR_SYMBOL_LIST(z), "exp");
106
1
  ccv_nnc_tensor_symbol_t sum = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "sum");
107
1
  ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_REDUCE_SUM_FORWARD(0), TENSOR_SYMBOL_LIST(z), TENSOR_SYMBOL_LIST(sum), "sum");
108
1
  ccv_nnc_tensor_symbol_t inv_sum = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "1 / sum");
109
1
  ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWDIV_FORWARD(), TENSOR_SYMBOL_LIST(NO_TENSOR_SYMBOL, sum), TENSOR_SYMBOL_LIST(inv_sum), "inv sum");
110
1
  ccv_nnc_tensor_symbol_t a = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 100), "a");
111
1
  ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_MUL_FORWARD(1), TENSOR_SYMBOL_LIST(z, inv_sum), TENSOR_SYMBOL_LIST(a), "softmax");
112
1
  ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
113
1
  ccv_nnc_symbolic_graph_backward(symbolic_graph, TENSOR_SYMBOL_LIST(a), TENSOR_SYMBOL_LIST(x), SYMBOLIC_GRAPH_SOURCES(symbolic_graph), SYMBOLIC_GRAPH_DESTINATIONS(symbolic_graph));
114
1
  ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
115
1
  ccv_nnc_tensor_symbol_t da = ccv_nnc_tensor_symbol_for_backward(symbolic_graph, a);
116
1
  ccv_nnc_tensor_symbol_t dx = ccv_nnc_tensor_symbol_for_backward(symbolic_graph, x);
117
1
  SYMBOLIC_GRAPH_GEN(symbolic_graph, CCV_NNC_LONG_DOT_GRAPH);
118
1
  ccv_nnc_graph_t* graph = 0;
119
1
  ccv_nnc_tensor_arena_t* tensor_arena = 0;
120
1
  ccv_nnc_graph_exec_arena_t* graph_exec_arena = 0;
121
1
  ccv_nnc_tensor_t* const a_tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 100), 0);
122
1
  ccv_nnc_tensor_t* const da_tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 100), 0);
123
1
  ccv_nnc_symbolic_graph_compile(symbolic_graph, ccv_nnc_default_compile_params, TENSOR_BIND_MAP(KV(a, a_tensor), KV(da, da_tensor)), 0, 0, SYMBOLIC_GRAPH_SOURCES(symbolic_graph), SYMBOLIC_GRAPH_DESTINATIONS(symbolic_graph), &graph, &tensor_arena, &graph_exec_arena);
124
1
  GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
125
1
  ccv_nnc_tensor_t* const tx_tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 100), 0);
126
1
  ccv_nnc_tensor_t* const x_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, x);
127
1
  dsfmt_t dsfmt;
128
1
  int i;
129
1
  dsfmt_init_gen_rand(&dsfmt, 1);
130
101
  for (i = 0; i < 100; 
i++100
)
131
100
    x_tensor->data.f32[i] = tx_tensor->data.f32[i] = dsfmt_genrand_open_close(&dsfmt);
132
101
  for (i = 0; i < 100; 
i++100
)
133
100
    da_tensor->data.f32[i] = 0;
134
1
  da_tensor->data.f32[88] = 1;
135
1
  ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0);
136
1
  ccv_nnc_tensor_t* const ta_tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 100), 0);
137
1
  ccv_nnc_cmd_exec(CMD_SOFTMAX_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_LIST(tx_tensor), TENSOR_LIST(ta_tensor), 0);
138
1
  REQUIRE_TENSOR_EQ(a_tensor, ta_tensor, "softmax should match from the graph");
139
1
  ccv_nnc_tensor_t* const tdx_tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 100), 0);
140
1
  ccv_nnc_cmd_exec(CMD_SOFTMAX_BACKWARD(), ccv_nnc_no_hint, 0, TENSOR_LIST(da_tensor, 0, ta_tensor), TENSOR_LIST(tdx_tensor), 0);
141
1
  ccv_nnc_tensor_t* const dx_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, dx);
142
1
  REQUIRE_TENSOR_EQ(dx_tensor, tdx_tensor, "softmax backward should match from the graph");
143
1
  ccv_nnc_tensor_free(tdx_tensor);
144
1
  ccv_nnc_tensor_free(tx_tensor);
145
1
  ccv_nnc_tensor_free(ta_tensor);
146
1
  ccv_nnc_tensor_free(a_tensor);
147
1
  ccv_nnc_tensor_free(da_tensor);
148
1
  ccv_nnc_symbolic_graph_free(symbolic_graph);
149
1
  ccv_nnc_graph_free(graph);
150
1
  ccv_nnc_tensor_arena_free(tensor_arena);
151
1
  ccv_nnc_graph_exec_arena_free(graph_exec_arena);
152
1
}
153
154
TEST_CASE("reduce max for [[1, 2, 3], [4, 5, 6]] on axis 1")
155
1
{
156
1
  ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
157
1
  ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 1), 0);
158
1
  a->data.f32[0] = 1;
159
1
  a->data.f32[1] = 2;
160
1
  a->data.f32[2] = 3;
161
1
  a->data.f32[3] = 4;
162
1
  a->data.f32[4] = 5;
163
1
  a->data.f32[5] = 6;
164
1
  ccv_nnc_cmd_exec(CMD_REDUCE_MAX_FORWARD(1), ccv_nnc_no_hint, 0, TENSOR_LIST(a), TENSOR_LIST(b), 0);
165
1
  float btp[] = {
166
1
    3,
167
1
    6
168
1
  };
169
1
  ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32F, 2, 1), 0);
170
1
  REQUIRE_TENSOR_EQ(b, &bt, "result should be equal");
171
1
  ccv_nnc_tensor_free(a);
172
1
  ccv_nnc_tensor_free(b);
173
1
}
174
175
TEST_CASE("reduce max for [[1, 2, 3], [4, 5, 6]] on axis 0")
176
1
{
177
1
  ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
178
1
  ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 3), 0);
179
1
  a->data.f32[0] = 1;
180
1
  a->data.f32[1] = 2;
181
1
  a->data.f32[2] = 3;
182
1
  a->data.f32[3] = 4;
183
1
  a->data.f32[4] = 5;
184
1
  a->data.f32[5] = 6;
185
1
  ccv_nnc_cmd_exec(CMD_REDUCE_MAX_FORWARD(0), ccv_nnc_no_hint, 0, TENSOR_LIST(a), TENSOR_LIST(b), 0);
186
1
  float btp[] = {
187
1
    4, 5, 6
188
1
  };
189
1
  ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32F, 3), 0);
190
1
  REQUIRE_TENSOR_EQ(b, &bt, "result should be equal");
191
1
  ccv_nnc_tensor_free(a);
192
1
  ccv_nnc_tensor_free(b);
193
1
}
194
195
TEST_CASE("reduce min for [[1, 2, 3], [4, 5, 6]] on axis 1")
196
1
{
197
1
  ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
198
1
  ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 1), 0);
199
1
  a->data.f32[0] = 1;
200
1
  a->data.f32[1] = 2;
201
1
  a->data.f32[2] = 3;
202
1
  a->data.f32[3] = 4;
203
1
  a->data.f32[4] = 5;
204
1
  a->data.f32[5] = 6;
205
1
  ccv_nnc_cmd_exec(CMD_REDUCE_MIN_FORWARD(1), ccv_nnc_no_hint, 0, TENSOR_LIST(a), TENSOR_LIST(b), 0);
206
1
  float btp[] = {
207
1
    1,
208
1
    4
209
1
  };
210
1
  ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32F, 2, 1), 0);
211
1
  REQUIRE_TENSOR_EQ(b, &bt, "result should be equal");
212
1
  ccv_nnc_tensor_free(a);
213
1
  ccv_nnc_tensor_free(b);
214
1
}
215
216
TEST_CASE("reduce min for [[1, 2, 3], [4, 5, 6]] on axis 0")
217
1
{
218
1
  ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
219
1
  ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 3), 0);
220
1
  a->data.f32[0] = 1;
221
1
  a->data.f32[1] = 2;
222
1
  a->data.f32[2] = 3;
223
1
  a->data.f32[3] = 4;
224
1
  a->data.f32[4] = 5;
225
1
  a->data.f32[5] = 6;
226
1
  ccv_nnc_cmd_exec(CMD_REDUCE_MIN_FORWARD(0), ccv_nnc_no_hint, 0, TENSOR_LIST(a), TENSOR_LIST(b), 0);
227
1
  float btp[] = {
228
1
    1, 2, 3
229
1
  };
230
1
  ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32F, 3), 0);
231
1
  REQUIRE_TENSOR_EQ(b, &bt, "result should be equal");
232
1
  ccv_nnc_tensor_free(a);
233
1
  ccv_nnc_tensor_free(b);
234
1
}
235
236
TEST_CASE("reduce sum for [[1, 2, 3], [4, 5, 6]] on axis 1 with model")
237
1
{
238
1
  ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
239
1
  ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 1), 0);
240
1
  a->data.f32[0] = 1;
241
1
  a->data.f32[1] = 2;
242
1
  a->data.f32[2] = 3;
243
1
  a->data.f32[3] = 4;
244
1
  a->data.f32[4] = 5;
245
1
  a->data.f32[5] = 6;
246
1
  const int axis = 1;
247
1
  ccv_cnnp_model_t* const reduce_sum = ccv_cnnp_reduce_sum(&axis, 1, 0);
248
1
  const ccv_nnc_tensor_param_t a_params = CPU_TENSOR_NHWC(32F, 2, 3);
249
1
  ccv_cnnp_model_compile(reduce_sum, TENSOR_PARAM_LIST(a_params), CMD_NOOP(), CMD_NOOP());
250
1
  ccv_cnnp_model_evaluate(reduce_sum, (ccv_cnnp_evaluate_param_t){
251
1
    .requires_grad = 0,
252
1
    .is_test = 0,
253
1
    .disable_outgrad = CCV_CNNP_DISABLE_OUTGRAD_ALL
254
1
  }, TENSOR_LIST(a), TENSOR_LIST(b), 0, 0);
255
1
  float btp[] = {
256
1
    6,
257
1
    15
258
1
  };
259
1
  ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32F, 2, 1), 0);
260
1
  REQUIRE_TENSOR_EQ(b, &bt, "result should be equal");
261
1
  ccv_cnnp_model_free(reduce_sum);
262
1
  ccv_nnc_tensor_free(a);
263
1
  ccv_nnc_tensor_free(b);
264
1
}
265
266
TEST_CASE("reduce max for [[1, 2, 3], [4, 5, 6]] on axis 0 with model")
267
1
{
268
1
  ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
269
1
  ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 3), 0);
270
1
  a->data.f32[0] = 1;
271
1
  a->data.f32[1] = 2;
272
1
  a->data.f32[2] = 3;
273
1
  a->data.f32[3] = 4;
274
1
  a->data.f32[4] = 5;
275
1
  a->data.f32[5] = 6;
276
1
  const int axis = 0;
277
1
  ccv_cnnp_model_t* const reduce_max = ccv_cnnp_reduce_max(&axis, 1, 0);
278
1
  const ccv_nnc_tensor_param_t a_params = CPU_TENSOR_NHWC(32F, 2, 3);
279
1
  ccv_cnnp_model_compile(reduce_max, TENSOR_PARAM_LIST(a_params), CMD_NOOP(), CMD_NOOP());
280
1
  ccv_cnnp_model_evaluate(reduce_max, (ccv_cnnp_evaluate_param_t){
281
1
    .requires_grad = 0,
282
1
    .is_test = 0,
283
1
    .disable_outgrad = CCV_CNNP_DISABLE_OUTGRAD_ALL
284
1
  }, TENSOR_LIST(a), TENSOR_LIST(b), 0, 0);
285
1
  float btp[] = {
286
1
    4, 5, 6
287
1
  };
288
1
  ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32F, 3), 0);
289
1
  REQUIRE_TENSOR_EQ(b, &bt, "result should be equal");
290
1
  ccv_cnnp_model_free(reduce_max);
291
1
  ccv_nnc_tensor_free(a);
292
1
  ccv_nnc_tensor_free(b);
293
1
}
294
295
TEST_CASE("reduce min for [[1, 2, 3], [4, 5, 6]] on axis 0 with model")
296
1
{
297
1
  ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
298
1
  ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 3), 0);
299
1
  a->data.f32[0] = 1;
300
1
  a->data.f32[1] = 2;
301
1
  a->data.f32[2] = 3;
302
1
  a->data.f32[3] = 4;
303
1
  a->data.f32[4] = 5;
304
1
  a->data.f32[5] = 6;
305
1
  const int axis = 0;
306
1
  ccv_cnnp_model_t* const reduce_min = ccv_cnnp_reduce_min(&axis, 1, 0);
307
1
  const ccv_nnc_tensor_param_t a_params = CPU_TENSOR_NHWC(32F, 2, 3);
308
1
  ccv_cnnp_model_compile(reduce_min, TENSOR_PARAM_LIST(a_params), CMD_NOOP(), CMD_NOOP());
309
1
  ccv_cnnp_model_evaluate(reduce_min, (ccv_cnnp_evaluate_param_t){
310
1
    .requires_grad = 0,
311
1
    .is_test = 0,
312
1
    .disable_outgrad = CCV_CNNP_DISABLE_OUTGRAD_ALL
313
1
  }, TENSOR_LIST(a), TENSOR_LIST(b), 0, 0);
314
1
  float btp[] = {
315
1
    1, 2, 3
316
1
  };
317
1
  ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32F, 3), 0);
318
1
  REQUIRE_TENSOR_EQ(b, &bt, "result should be equal");
319
1
  ccv_cnnp_model_free(reduce_min);
320
1
  ccv_nnc_tensor_free(a);
321
1
  ccv_nnc_tensor_free(b);
322
1
}
323
324
TEST_CASE("argmax for [[1, 2, 3], [4, 5, 2]] on axis 0 with model")
325
1
{
326
1
  ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
327
1
  ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32S, 3), 0);
328
1
  a->data.f32[0] = 1;
329
1
  a->data.f32[1] = 2;
330
1
  a->data.f32[2] = 3;
331
1
  a->data.f32[3] = 4;
332
1
  a->data.f32[4] = 5;
333
1
  a->data.f32[5] = 2;
334
1
  ccv_cnnp_model_t* const argmax = ccv_cnnp_argmax(0, 0);
335
1
  const ccv_nnc_tensor_param_t a_params = CPU_TENSOR_NHWC(32F, 2, 3);
336
1
  ccv_cnnp_model_compile(argmax, TENSOR_PARAM_LIST(a_params), CMD_NOOP(), CMD_NOOP());
337
1
  ccv_cnnp_model_evaluate(argmax, (ccv_cnnp_evaluate_param_t){
338
1
    .requires_grad = 0,
339
1
    .is_test = 0,
340
1
    .disable_outgrad = CCV_CNNP_DISABLE_OUTGRAD_ALL
341
1
  }, TENSOR_LIST(a), TENSOR_LIST(b), 0, 0);
342
1
  int btp[] = {
343
1
    1, 1, 0
344
1
  };
345
1
  ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32S, 3), 0);
346
1
  REQUIRE_TENSOR_EQ(b, &bt, "result should be equal");
347
1
  ccv_cnnp_model_free(argmax);
348
1
  ccv_nnc_tensor_free(a);
349
1
  ccv_nnc_tensor_free(b);
350
1
}
351
352
TEST_CASE("argmin for [[1, 2, 3], [4, 5, 2]] on axis 0 with model")
353
1
{
354
1
  ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
355
1
  ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32S, 3), 0);
356
1
  a->data.f32[0] = 1;
357
1
  a->data.f32[1] = 2;
358
1
  a->data.f32[2] = 3;
359
1
  a->data.f32[3] = 4;
360
1
  a->data.f32[4] = 5;
361
1
  a->data.f32[5] = 2;
362
1
  ccv_cnnp_model_t* const argmin = ccv_cnnp_argmin(0, 0);
363
1
  const ccv_nnc_tensor_param_t a_params = CPU_TENSOR_NHWC(32F, 2, 3);
364
1
  ccv_cnnp_model_compile(argmin, TENSOR_PARAM_LIST(a_params), CMD_NOOP(), CMD_NOOP());
365
1
  ccv_cnnp_model_evaluate(argmin, (ccv_cnnp_evaluate_param_t){
366
1
    .requires_grad = 0,
367
1
    .is_test = 0,
368
1
    .disable_outgrad = CCV_CNNP_DISABLE_OUTGRAD_ALL
369
1
  }, TENSOR_LIST(a), TENSOR_LIST(b), 0, 0);
370
1
  int btp[] = {
371
1
    0, 0, 1
372
1
  };
373
1
  ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32S, 3), 0);
374
1
  REQUIRE_TENSOR_EQ(b, &bt, "result should be equal");
375
1
  ccv_cnnp_model_free(argmin);
376
1
  ccv_nnc_tensor_free(a);
377
1
  ccv_nnc_tensor_free(b);
378
1
}
379
380
TEST_CASE("reduce mean for [[1, 2, 3], [4, 5, 6]] on axis 1 with model")
381
1
{
382
1
  ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
383
1
  ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 1), 0);
384
1
  a->data.f32[0] = 1;
385
1
  a->data.f32[1] = 2;
386
1
  a->data.f32[2] = 3;
387
1
  a->data.f32[3] = 4;
388
1
  a->data.f32[4] = 5;
389
1
  a->data.f32[5] = 6;
390
1
  const int axis = 1;
391
1
  ccv_cnnp_model_t* const reduce_mean = ccv_cnnp_reduce_mean(&axis, 1, 0);
392
1
  const ccv_nnc_tensor_param_t a_params = CPU_TENSOR_NHWC(32F, 2, 3);
393
1
  ccv_cnnp_model_compile(reduce_mean, TENSOR_PARAM_LIST(a_params), CMD_NOOP(), CMD_NOOP());
394
1
  ccv_cnnp_model_evaluate(reduce_mean, (ccv_cnnp_evaluate_param_t){
395
1
    .requires_grad = 0,
396
1
    .is_test = 0,
397
1
    .disable_outgrad = CCV_CNNP_DISABLE_OUTGRAD_ALL
398
1
  }, TENSOR_LIST(a), TENSOR_LIST(b), 0, 0);
399
1
  float btp[] = {
400
1
    2,
401
1
    5
402
1
  };
403
1
  ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32F, 2, 1), 0);
404
1
  REQUIRE_TENSOR_EQ(b, &bt, "result should be equal");
405
1
  ccv_cnnp_model_free(reduce_mean);
406
1
  ccv_nnc_tensor_free(a);
407
1
  ccv_nnc_tensor_free(b);
408
1
}
409
410
TEST_CASE("argmax for [[1, 2, 7], [5, 6, 4]] on axis 0")
411
1
{
412
1
  ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
413
1
  ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32S, 3), 0);
414
1
  a->data.f32[0] = 1;
415
1
  a->data.f32[1] = 2;
416
1
  a->data.f32[2] = 7;
417
1
  a->data.f32[3] = 5;
418
1
  a->data.f32[4] = 6;
419
1
  a->data.f32[5] = 4;
420
1
  ccv_nnc_cmd_exec(CMD_ARGMAX_FORWARD(0), ccv_nnc_no_hint, 0, TENSOR_LIST(a), TENSOR_LIST(b), 0);
421
1
  int btp[] = {
422
1
    1, 1, 0
423
1
  };
424
1
  ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32S, 3), 0);
425
1
  REQUIRE_TENSOR_EQ(b, &bt, "result should be equal");
426
1
  ccv_nnc_tensor_free(a);
427
1
  ccv_nnc_tensor_free(b);
428
1
}
429
430
TEST_CASE("argmin for [[1, 2, 7], [5, 6, 4]] on axis 0")
431
1
{
432
1
  ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
433
1
  ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32S, 3), 0);
434
1
  a->data.f32[0] = 1;
435
1
  a->data.f32[1] = 2;
436
1
  a->data.f32[2] = 7;
437
1
  a->data.f32[3] = 5;
438
1
  a->data.f32[4] = 6;
439
1
  a->data.f32[5] = 4;
440
1
  ccv_nnc_cmd_exec(CMD_ARGMIN_FORWARD(0), ccv_nnc_no_hint, 0, TENSOR_LIST(a), TENSOR_LIST(b), 0);
441
1
  int btp[] = {
442
1
    0, 0, 1
443
1
  };
444
1
  ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32S, 3), 0);
445
1
  REQUIRE_TENSOR_EQ(b, &bt, "result should be equal");
446
1
  ccv_nnc_tensor_free(a);
447
1
  ccv_nnc_tensor_free(b);
448
1
}
449
450
TEST_CASE("argmax for [[1, 2, 7], [5, 6, 4]] on axis 1")
451
1
{
452
1
  ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
453
1
  ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32S, 2, 1), 0);
454
1
  a->data.f32[0] = 1;
455
1
  a->data.f32[1] = 2;
456
1
  a->data.f32[2] = 7;
457
1
  a->data.f32[3] = 5;
458
1
  a->data.f32[4] = 6;
459
1
  a->data.f32[5] = 4;
460
1
  ccv_nnc_cmd_exec(CMD_ARGMAX_FORWARD(1), ccv_nnc_no_hint, 0, TENSOR_LIST(a), TENSOR_LIST(b), 0);
461
1
  int btp[] = {
462
1
    2,
463
1
    1
464
1
  };
465
1
  ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32S, 2, 1), 0);
466
1
  REQUIRE_TENSOR_EQ(b, &bt, "result should be equal");
467
1
  ccv_nnc_tensor_free(a);
468
1
  ccv_nnc_tensor_free(b);
469
1
}
470
471
TEST_CASE("reduce norm2 for [[1, 2, 3], [4, 5, 6]] on axis 1")
472
1
{
473
1
  ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
474
1
  ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 1), 0);
475
1
  a->data.f32[0] = 1;
476
1
  a->data.f32[1] = 2;
477
1
  a->data.f32[2] = 3;
478
1
  a->data.f32[3] = 4;
479
1
  a->data.f32[4] = 5;
480
1
  a->data.f32[5] = 6;
481
1
  ccv_nnc_cmd_exec(CMD_REDUCE_NORM2_FORWARD(1), ccv_nnc_no_hint, 0, TENSOR_LIST(a), TENSOR_LIST(b), 0);
482
1
  float btp[] = {
483
1
    sqrt(1 + 2 * 2 + 3 * 3),
484
1
    sqrt(4 * 4 + 5 * 5 + 6 * 6)
485
1
  };
486
1
  ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32F, 2, 1), 0);
487
1
  REQUIRE_TENSOR_EQ(b, &bt, "result should be equal");
488
1
  ccv_nnc_tensor_free(a);
489
1
  ccv_nnc_tensor_free(b);
490
1
}
491
492
TEST_CASE("reduce norm2 for [[1, 2, 3], [4, 5, 6]] on axis 0")
493
1
{
494
1
  ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
495
1
  ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 3), 0);
496
1
  a->data.f32[0] = 1;
497
1
  a->data.f32[1] = 2;
498
1
  a->data.f32[2] = 3;
499
1
  a->data.f32[3] = 4;
500
1
  a->data.f32[4] = 5;
501
1
  a->data.f32[5] = 6;
502
1
  ccv_nnc_cmd_exec(CMD_REDUCE_NORM2_FORWARD(0), ccv_nnc_no_hint, 0, TENSOR_LIST(a), TENSOR_LIST(b), 0);
503
1
  float btp[] = {
504
1
    sqrt(1 + 4 * 4), sqrt(2 * 2 + 5 * 5), sqrt(3 * 3 + 6 * 6)
505
1
  };
506
1
  ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32F, 3), 0);
507
1
  REQUIRE_TENSOR_EQ(b, &bt, "result should be equal");
508
1
  ccv_nnc_tensor_free(a);
509
1
  ccv_nnc_tensor_free(b);
510
1
}
511
512
TEST_CASE("reduce norm2 for [[1, 2, 3], [4, 5, 6]] on axis 1 backward")
513
1
{
514
1
  ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
515
1
  ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 1), 0);
516
1
  a->data.f32[0] = 1;
517
1
  a->data.f32[1] = 2;
518
1
  a->data.f32[2] = 3;
519
1
  a->data.f32[3] = 4;
520
1
  a->data.f32[4] = 5;
521
1
  a->data.f32[5] = 6;
522
1
  ccv_nnc_cmd_exec(CMD_REDUCE_NORM2_FORWARD(1), ccv_nnc_no_hint, 0, TENSOR_LIST(a), TENSOR_LIST(b), 0);
523
1
  ccv_nnc_tensor_t* const g = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 1), 0);
524
1
  g->data.f32[0] = 0.5;
525
1
  g->data.f32[1] = 0.5;
526
1
  ccv_nnc_tensor_t* const h = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
527
1
  ccv_nnc_cmd_exec(CMD_REDUCE_NORM2_BACKWARD(1), ccv_nnc_no_hint, 0, TENSOR_LIST(g, a, b), TENSOR_LIST(h), 0);
528
1
  float htp[] = {
529
1
    0.5 * 1 / sqrt(1 + 2 * 2 + 3 * 3),
530
1
    0.5 * 2 / sqrt(1 + 2 * 2 + 3 * 3),
531
1
    0.5 * 3 / sqrt(1 + 2 * 2 + 3 * 3),
532
1
    0.5 * 4 / sqrt(4 * 4 + 5 * 5 + 6 * 6),
533
1
    0.5 * 5 / sqrt(4 * 4 + 5 * 5 + 6 * 6),
534
1
    0.5 * 6 / sqrt(4 * 4 + 5 * 5 + 6 * 6),
535
1
  };
536
1
  ccv_nnc_tensor_t ht = ccv_nnc_tensor(htp, CPU_TENSOR_NHWC(32F, 2, 3), 0);
537
1
  REQUIRE_TENSOR_EQ(h, &ht, "result should be equal");
538
1
  ccv_nnc_tensor_free(a);
539
1
  ccv_nnc_tensor_free(b);
540
1
  ccv_nnc_tensor_free(g);
541
1
  ccv_nnc_tensor_free(h);
542
1
}
543
544
TEST_CASE("reduce norm2 for [[1, 2, 3], [4, 5, 6]] on axis 0 backward")
545
1
{
546
1
  ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
547
1
  ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 3), 0);
548
1
  a->data.f32[0] = 1;
549
1
  a->data.f32[1] = 2;
550
1
  a->data.f32[2] = 3;
551
1
  a->data.f32[3] = 4;
552
1
  a->data.f32[4] = 5;
553
1
  a->data.f32[5] = 6;
554
1
  ccv_nnc_cmd_exec(CMD_REDUCE_NORM2_FORWARD(0), ccv_nnc_no_hint, 0, TENSOR_LIST(a), TENSOR_LIST(b), 0);
555
1
  ccv_nnc_tensor_t* const g = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 3), 0);
556
1
  g->data.f32[0] = 1;
557
1
  g->data.f32[1] = 1;
558
1
  g->data.f32[2] = 1;
559
1
  ccv_nnc_tensor_t* const h = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
560
1
  ccv_nnc_cmd_exec(CMD_REDUCE_NORM2_BACKWARD(0), ccv_nnc_no_hint, 0, TENSOR_LIST(g, a, b), TENSOR_LIST(h), 0);
561
1
  float htp[] = {
562
1
    1 / sqrt(1 + 4 * 4), 2 / sqrt(2 * 2 + 5 * 5), 3 / sqrt(3 * 3 + 6 * 6),
563
1
    4 / sqrt(1 + 4 * 4), 5 / sqrt(2 * 2 + 5 * 5), 6 / sqrt(3 * 3 + 6 * 6)
564
1
  };
565
1
  ccv_nnc_tensor_t ht = ccv_nnc_tensor(htp, CPU_TENSOR_NHWC(32F, 2, 3), 0);
566
1
  REQUIRE_TENSOR_EQ(h, &ht, "result should be equal");
567
1
  ccv_nnc_tensor_free(a);
568
1
  ccv_nnc_tensor_free(b);
569
1
  ccv_nnc_tensor_free(g);
570
1
  ccv_nnc_tensor_free(h);
571
1
}
572
573
TEST_CASE("reduce norm2 for [[1, 2, 3], [4, 5, 6]] on axis 0 with model")
574
1
{
575
1
  ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
576
1
  ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 3), 0);
577
1
  a->data.f32[0] = 1;
578
1
  a->data.f32[1] = 2;
579
1
  a->data.f32[2] = 3;
580
1
  a->data.f32[3] = 4;
581
1
  a->data.f32[4] = 5;
582
1
  a->data.f32[5] = 6;
583
1
  const int axis = 0;
584
1
  ccv_cnnp_model_t* const reduce_norm2 = ccv_cnnp_reduce_norm2(&axis, 1, 0);
585
1
  const ccv_nnc_tensor_param_t a_params = CPU_TENSOR_NHWC(32F, 2, 3);
586
1
  ccv_cnnp_model_compile(reduce_norm2, TENSOR_PARAM_LIST(a_params), CMD_NOOP(), CMD_NOOP());
587
1
  ccv_cnnp_model_evaluate(reduce_norm2, (ccv_cnnp_evaluate_param_t){
588
1
    .requires_grad = 0,
589
1
    .is_test = 0,
590
1
    .disable_outgrad = CCV_CNNP_DISABLE_OUTGRAD_ALL
591
1
  }, TENSOR_LIST(a), TENSOR_LIST(b), 0, 0);
592
1
  float btp[] = {
593
1
    sqrt(1 + 4 * 4), sqrt(2 * 2 + 5 * 5), sqrt(3 * 3 + 6 * 6)
594
1
  };
595
1
  ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32F, 3), 0);
596
1
  REQUIRE_TENSOR_EQ(b, &bt, "result should be equal");
597
1
  ccv_cnnp_model_free(reduce_norm2);
598
1
  ccv_nnc_tensor_free(a);
599
1
  ccv_nnc_tensor_free(b);
600
1
}
601
602
TEST_CASE("isnan for [[1, 2, 3], [4, 5, 6]] on axis 1")
603
1
{
604
1
  ccv_nnc_tensor_t* const a = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0);
605
1
  ccv_nnc_tensor_t* const b = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32S, 2, 1), 0);
606
1
  a->data.f32[0] = NAN;
607
1
  a->data.f32[1] = 2;
608
1
  a->data.f32[2] = 3;
609
1
  a->data.f32[3] = 4;
610
1
  a->data.f32[4] = 5;
611
1
  a->data.f32[5] = 6;
612
1
  ccv_nnc_cmd_exec(CMD_REDUCE_ISNAN_FORWARD(1), ccv_nnc_no_hint, 0, TENSOR_LIST(a), TENSOR_LIST(b), 0);
613
1
  int btp[] = {
614
1
    1,
615
1
    0
616
1
  };
617
1
  ccv_nnc_tensor_t bt = ccv_nnc_tensor(btp, CPU_TENSOR_NHWC(32S, 2, 1), 0);
618
1
  REQUIRE_TENSOR_EQ(b, &bt, "result should be equal");
619
1
  ccv_nnc_tensor_free(a);
620
1
  ccv_nnc_tensor_free(b);
621
1
}
622
623
#include "case_main.h"