Coverage Report

Created: 2024-08-19 11:27

/home/liu/actions-runner/_work/ccv/ccv/test/unit/nnc/crossentropy.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
8
TEST_SETUP()
9
{
10
  ccv_nnc_init();
11
}
12
13
TEST_CASE("compare softmax + categorical crossentropy v.s. softmax crossentropy command")
14
1
{
15
1
  ccv_nnc_symbolic_graph_t* const graph = ccv_nnc_symbolic_graph_new();
16
  // batch size = 2, dim = 3.
17
1
  const ccv_nnc_tensor_symbol_t a = ccv_nnc_tensor_symbol_new(graph, CPU_TENSOR_NHWC(32F, 2, 3), "a");
18
1
  const ccv_nnc_tensor_symbol_t b0 = ccv_nnc_tensor_symbol_new(graph, CPU_TENSOR_NHWC(32F, 2, 3), "b0");
19
1
  ccv_nnc_graph_exec_symbol_new(graph, CMD_SOFTMAX_FORWARD(), TENSOR_SYMBOL_LIST(a), TENSOR_SYMBOL_LIST(b0), "softmax");
20
1
  const ccv_nnc_tensor_symbol_t label = ccv_nnc_tensor_symbol_new(graph, CPU_TENSOR_NHWC(32S, 2), "label");
21
1
  const ccv_nnc_tensor_symbol_t loss0 = ccv_nnc_tensor_symbol_new(graph, ccv_nnc_tensor_auto, "loss0");
22
1
  ccv_nnc_graph_exec_symbol_new(graph, CMD_CATEGORICAL_CROSSENTROPY_FORWARD(), TENSOR_SYMBOL_LIST(b0, label), TENSOR_SYMBOL_LIST(loss0), "categorical crossentropy");
23
1
  const ccv_nnc_tensor_symbol_t b1 = ccv_nnc_tensor_symbol_new(graph, CPU_TENSOR_NHWC(32F, 2, 3), "b1");
24
1
  const ccv_nnc_tensor_symbol_t loss1 = ccv_nnc_tensor_symbol_new(graph, ccv_nnc_tensor_auto, "loss1");
25
1
  ccv_nnc_graph_exec_symbol_new(graph, CMD_SOFTMAX_CROSSENTROPY_FORWARD(), TENSOR_SYMBOL_LIST(a, label), TENSOR_SYMBOL_LIST(loss1, b1), "softmax crossentropy");
26
1
  ccv_nnc_graph_exec_symbol_autogen(graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
27
1
  ccv_nnc_symbolic_graph_backward(graph, TENSOR_SYMBOL_LIST(loss0), TENSOR_SYMBOL_LIST(a), SYMBOLIC_GRAPH_SOURCES(graph), SYMBOLIC_GRAPH_DESTINATIONS(graph));
28
1
  const ccv_nnc_tensor_symbol_t dloss0 = ccv_nnc_tensor_symbol_for_backward(graph, loss0);
29
1
  const ccv_nnc_tensor_symbol_t da0 = ccv_nnc_tensor_symbol_for_backward(graph, a);
30
1
  ccv_nnc_symbolic_graph_backward(graph, TENSOR_SYMBOL_LIST(loss1), TENSOR_SYMBOL_LIST(a), SYMBOLIC_GRAPH_SOURCES(graph), SYMBOLIC_GRAPH_DESTINATIONS(graph));
31
1
  const ccv_nnc_tensor_symbol_t dloss1 = ccv_nnc_tensor_symbol_for_backward(graph, loss1);
32
1
  ccv_nnc_graph_exec_symbol_new(graph, CMD_SET_FORWARD(1), 0, 0, TENSOR_SYMBOL_LIST(dloss0, dloss1), "set 1");
33
1
  const ccv_nnc_tensor_symbol_t da1 = ccv_nnc_tensor_symbol_for_backward(graph, a);
34
1
  ccv_nnc_graph_exec_symbol_autogen(graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
35
1
  SYMBOLIC_GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
36
1
  ccv_nnc_graph_t* run_graph;
37
1
  ccv_nnc_tensor_arena_t* tensor_arena;
38
1
  ccv_nnc_graph_exec_arena_t* graph_exec_arena;
39
1
  ccv_nnc_symbolic_graph_compile(graph, ccv_nnc_default_compile_params,
40
1
    0, 0,
41
1
    TENSOR_SYMBOL_LIST(loss0, loss1, da0, da1),
42
1
    SYMBOLIC_GRAPH_SOURCES(graph), SYMBOLIC_GRAPH_DESTINATIONS(graph),
43
1
    &run_graph, &tensor_arena, &graph_exec_arena);
44
1
  ccv_nnc_tensor_t* const a_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, a);
45
1
  a_tensor->data.f32[0] = 10;
46
1
  a_tensor->data.f32[1] = -1;
47
1
  a_tensor->data.f32[2] = -5;
48
1
  a_tensor->data.f32[3] = 12;
49
1
  a_tensor->data.f32[4] = 4;
50
1
  a_tensor->data.f32[5] = 24;
51
1
  ccv_nnc_tensor_t* const label_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, label);
52
1
  label_tensor->data.i32[0] = 2;
53
1
  label_tensor->data.i32[1] = 1;
54
1
  ccv_nnc_graph_run(run_graph, 0, TRAVERSE_FULL, 0, 0);
55
1
  ccv_nnc_tensor_t* const da0_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, da0);
56
1
  ccv_nnc_tensor_t* const da1_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, da1);
57
1
  REQUIRE_TENSOR_EQ(da0_tensor, da1_tensor, "two tensors from combined op and separate ops should be equal");
58
1
  ccv_nnc_tensor_t* const loss0_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, loss0);
59
1
  ccv_nnc_tensor_t* const loss1_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, loss1);
60
1
  REQUIRE_TENSOR_EQ(loss0_tensor, loss1_tensor, "two tensors from combined op and separate ops should be equal");
61
1
  ccv_nnc_graph_free(run_graph);
62
1
  ccv_nnc_tensor_arena_free(tensor_arena);
63
1
  ccv_nnc_graph_exec_arena_free(graph_exec_arena);
64
1
  ccv_nnc_symbolic_graph_free(graph);
65
1
}
66
67
TEST_CASE("compare label smoothing with one hot and label for categorical crossentropy command")
68
1
{
69
1
  ccv_nnc_symbolic_graph_t* const graph = ccv_nnc_symbolic_graph_new();
70
  // batch size = 2, dim = 3.
71
1
  const ccv_nnc_tensor_symbol_t a = ccv_nnc_tensor_symbol_new(graph, CPU_TENSOR_NHWC(32F, 2, 3), "a");
72
1
  const ccv_nnc_tensor_symbol_t oh = ccv_nnc_tensor_symbol_new(graph, CPU_TENSOR_NHWC(32F, 2, 3), "oh");
73
1
  const ccv_nnc_tensor_symbol_t loss0 = ccv_nnc_tensor_symbol_new(graph, ccv_nnc_tensor_auto, "loss0");
74
1
  ccv_nnc_graph_exec_symbol_new(graph, CMD_CATEGORICAL_CROSSENTROPY_FORWARD(0.1, 0.9), TENSOR_SYMBOL_LIST(a, oh), TENSOR_SYMBOL_LIST(loss0), "categorical with one hot");
75
1
  const ccv_nnc_tensor_symbol_t label = ccv_nnc_tensor_symbol_new(graph, CPU_TENSOR_NHWC(32S, 2, 1), "label");
76
1
  const ccv_nnc_tensor_symbol_t loss1 = ccv_nnc_tensor_symbol_new(graph, ccv_nnc_tensor_auto, "loss1");
77
1
  ccv_nnc_graph_exec_symbol_new(graph, CMD_CATEGORICAL_CROSSENTROPY_FORWARD(0.1, 0.9), TENSOR_SYMBOL_LIST(a, label), TENSOR_SYMBOL_LIST(loss1), "categorical with label");
78
1
  ccv_nnc_graph_exec_symbol_autogen(graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
79
1
  ccv_nnc_symbolic_graph_backward(graph, TENSOR_SYMBOL_LIST(loss0), TENSOR_SYMBOL_LIST(a), SYMBOLIC_GRAPH_SOURCES(graph), SYMBOLIC_GRAPH_DESTINATIONS(graph));
80
1
  const ccv_nnc_tensor_symbol_t dloss0 = ccv_nnc_tensor_symbol_for_backward(graph, loss0);
81
1
  const ccv_nnc_tensor_symbol_t da0 = ccv_nnc_tensor_symbol_for_backward(graph, a);
82
1
  ccv_nnc_symbolic_graph_backward(graph, TENSOR_SYMBOL_LIST(loss1), TENSOR_SYMBOL_LIST(a), SYMBOLIC_GRAPH_SOURCES(graph), SYMBOLIC_GRAPH_DESTINATIONS(graph));
83
1
  const ccv_nnc_tensor_symbol_t dloss1 = ccv_nnc_tensor_symbol_for_backward(graph, loss1);
84
1
  const ccv_nnc_tensor_symbol_t da1 = ccv_nnc_tensor_symbol_for_backward(graph, a);
85
1
  ccv_nnc_graph_exec_symbol_new(graph, CMD_SET_FORWARD(1), 0, 0, TENSOR_SYMBOL_LIST(dloss0, dloss1), "set 1");
86
1
  ccv_nnc_graph_exec_symbol_autogen(graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
87
1
  SYMBOLIC_GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
88
1
  ccv_nnc_graph_t* run_graph;
89
1
  ccv_nnc_tensor_arena_t* tensor_arena;
90
1
  ccv_nnc_graph_exec_arena_t* graph_exec_arena;
91
1
  ccv_nnc_symbolic_graph_compile(graph, ccv_nnc_default_compile_params,
92
1
    0, 0,
93
1
    TENSOR_SYMBOL_LIST(loss0, loss1, da0, da1),
94
1
    SYMBOLIC_GRAPH_SOURCES(graph), SYMBOLIC_GRAPH_DESTINATIONS(graph), &run_graph, &tensor_arena, &graph_exec_arena);
95
1
  ccv_nnc_tensor_t* const a_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, a);
96
1
  a_tensor->data.f32[0] = 10;
97
1
  a_tensor->data.f32[1] = -2;
98
1
  a_tensor->data.f32[2] = -5;
99
1
  a_tensor->data.f32[3] = -12;
100
1
  a_tensor->data.f32[4] = 4;
101
1
  a_tensor->data.f32[5] = 24;
102
1
  ccv_nnc_tensor_t* const oh_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, oh);
103
1
  oh_tensor->data.f32[0] = 0.1;
104
1
  oh_tensor->data.f32[1] = 0.1;
105
1
  oh_tensor->data.f32[2] = 0.9;
106
1
  oh_tensor->data.f32[3] = 0.1;
107
1
  oh_tensor->data.f32[4] = 0.9;
108
1
  oh_tensor->data.f32[5] = 0.1;
109
1
  ccv_nnc_tensor_t* const label_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, label);
110
1
  label_tensor->data.i32[0] = 2;
111
1
  label_tensor->data.i32[1] = 1;
112
1
  ccv_nnc_graph_run(run_graph, 0, TRAVERSE_FULL, 0, 0);
113
1
  ccv_nnc_tensor_t* const loss0_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, loss0);
114
1
  ccv_nnc_tensor_t* const loss1_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, loss1);
115
1
  REQUIRE_TENSOR_EQ(loss0_tensor, loss1_tensor, "two tensors from one hot and label with smoothing should be equal");
116
1
  ccv_nnc_tensor_t* const da0_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, da0);
117
1
  ccv_nnc_tensor_t* const da1_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, da1);
118
1
  REQUIRE_TENSOR_EQ(da0_tensor, da1_tensor, "two tensors from one hot and label with smoothing should be equal");
119
1
  ccv_nnc_graph_free(run_graph);
120
1
  ccv_nnc_tensor_arena_free(tensor_arena);
121
1
  ccv_nnc_graph_exec_arena_free(graph_exec_arena);
122
1
  ccv_nnc_symbolic_graph_free(graph);
123
1
}
124
125
TEST_CASE("compare label smoothing with one hot and label for softmax crossentropy command")
126
1
{
127
1
  ccv_nnc_symbolic_graph_t* const graph = ccv_nnc_symbolic_graph_new();
128
  // batch size = 2, dim = 3.
129
1
  const ccv_nnc_tensor_symbol_t a = ccv_nnc_tensor_symbol_new(graph, CPU_TENSOR_NHWC(32F, 2, 3), "a");
130
1
  const ccv_nnc_tensor_symbol_t oh = ccv_nnc_tensor_symbol_new(graph, CPU_TENSOR_NHWC(32F, 2, 3), "oh");
131
1
  const ccv_nnc_tensor_symbol_t b0 = ccv_nnc_tensor_symbol_new(graph, ccv_nnc_tensor_auto, "b0");
132
1
  const ccv_nnc_tensor_symbol_t loss0 = ccv_nnc_tensor_symbol_new(graph, ccv_nnc_tensor_auto, "loss0");
133
1
  ccv_nnc_graph_exec_symbol_new(graph, CMD_SOFTMAX_CROSSENTROPY_FORWARD(0.1, 0.9), TENSOR_SYMBOL_LIST(a, oh), TENSOR_SYMBOL_LIST(loss0, b0), "softmax with one hot");
134
1
  const ccv_nnc_tensor_symbol_t label = ccv_nnc_tensor_symbol_new(graph, CPU_TENSOR_NHWC(32S, 2, 1), "label");
135
1
  const ccv_nnc_tensor_symbol_t b1 = ccv_nnc_tensor_symbol_new(graph, ccv_nnc_tensor_auto, "b1");
136
1
  const ccv_nnc_tensor_symbol_t loss1 = ccv_nnc_tensor_symbol_new(graph, ccv_nnc_tensor_auto, "loss1");
137
1
  ccv_nnc_graph_exec_symbol_new(graph, CMD_SOFTMAX_CROSSENTROPY_FORWARD(0.1, 0.9), TENSOR_SYMBOL_LIST(a, label), TENSOR_SYMBOL_LIST(loss1, b1), "softmax with label");
138
1
  ccv_nnc_graph_exec_symbol_autogen(graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
139
1
  ccv_nnc_symbolic_graph_backward(graph, TENSOR_SYMBOL_LIST(loss0), TENSOR_SYMBOL_LIST(a), SYMBOLIC_GRAPH_SOURCES(graph), SYMBOLIC_GRAPH_DESTINATIONS(graph));
140
1
  const ccv_nnc_tensor_symbol_t dloss0 = ccv_nnc_tensor_symbol_for_backward(graph, loss0);
141
1
  const ccv_nnc_tensor_symbol_t da0 = ccv_nnc_tensor_symbol_for_backward(graph, a);
142
1
  ccv_nnc_symbolic_graph_backward(graph, TENSOR_SYMBOL_LIST(loss1), TENSOR_SYMBOL_LIST(a), SYMBOLIC_GRAPH_SOURCES(graph), SYMBOLIC_GRAPH_DESTINATIONS(graph));
143
1
  const ccv_nnc_tensor_symbol_t dloss1 = ccv_nnc_tensor_symbol_for_backward(graph, loss1);
144
1
  const ccv_nnc_tensor_symbol_t da1 = ccv_nnc_tensor_symbol_for_backward(graph, a);
145
1
  ccv_nnc_graph_exec_symbol_new(graph, CMD_SET_FORWARD(1), 0, 0, TENSOR_SYMBOL_LIST(dloss0, dloss1), "set 1");
146
1
  ccv_nnc_graph_exec_symbol_autogen(graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
147
1
  SYMBOLIC_GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
148
1
  ccv_nnc_graph_t* run_graph;
149
1
  ccv_nnc_tensor_arena_t* tensor_arena;
150
1
  ccv_nnc_graph_exec_arena_t* graph_exec_arena;
151
1
  ccv_nnc_symbolic_graph_compile(graph, ccv_nnc_default_compile_params,
152
1
    0, 0,
153
1
    TENSOR_SYMBOL_LIST(loss0, loss1, b0, b1, da0, da1),
154
1
    SYMBOLIC_GRAPH_SOURCES(graph), SYMBOLIC_GRAPH_DESTINATIONS(graph), &run_graph, &tensor_arena, &graph_exec_arena);
155
1
  ccv_nnc_tensor_t* const a_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, a);
156
1
  a_tensor->data.f32[0] = 10;
157
1
  a_tensor->data.f32[1] = -2;
158
1
  a_tensor->data.f32[2] = -5;
159
1
  a_tensor->data.f32[3] = -12;
160
1
  a_tensor->data.f32[4] = 4;
161
1
  a_tensor->data.f32[5] = 24;
162
1
  ccv_nnc_tensor_t* const oh_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, oh);
163
1
  oh_tensor->data.f32[0] = 0.1;
164
1
  oh_tensor->data.f32[1] = 0.1;
165
1
  oh_tensor->data.f32[2] = 0.9;
166
1
  oh_tensor->data.f32[3] = 0.1;
167
1
  oh_tensor->data.f32[4] = 0.9;
168
1
  oh_tensor->data.f32[5] = 0.1;
169
1
  ccv_nnc_tensor_t* const label_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, label);
170
1
  label_tensor->data.i32[0] = 2;
171
1
  label_tensor->data.i32[1] = 1;
172
1
  ccv_nnc_graph_run(run_graph, 0, TRAVERSE_FULL, 0, 0);
173
1
  ccv_nnc_tensor_t* const loss0_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, loss0);
174
1
  ccv_nnc_tensor_t* const loss1_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, loss1);
175
1
  REQUIRE_TENSOR_EQ(loss0_tensor, loss1_tensor, "two tensors from one hot and label with smoothing should be equal");
176
1
  ccv_nnc_tensor_t* const b0_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, b0);
177
1
  ccv_nnc_tensor_t* const b1_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, b1);
178
1
  REQUIRE_TENSOR_EQ(b0_tensor, b1_tensor, "two tensors from one hot and label with smoothing should be equal");
179
1
  ccv_nnc_tensor_t* const da0_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, da0);
180
1
  ccv_nnc_tensor_t* const da1_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, da1);
181
1
  REQUIRE_TENSOR_EQ(da0_tensor, da1_tensor, "two tensors from one hot and label with smoothing should be equal");
182
1
  ccv_nnc_graph_free(run_graph);
183
1
  ccv_nnc_tensor_arena_free(tensor_arena);
184
1
  ccv_nnc_graph_exec_arena_free(graph_exec_arena);
185
1
  ccv_nnc_symbolic_graph_free(graph);
186
1
}
187
188
TEST_CASE("compare sigmoid + binary entropy v.s. sigmoid binary entropy command")
189
1
{
190
1
  ccv_nnc_symbolic_graph_t* const graph = ccv_nnc_symbolic_graph_new();
191
  // batch size = 2, dim = 3.
192
1
  const ccv_nnc_tensor_symbol_t a = ccv_nnc_tensor_symbol_new(graph, CPU_TENSOR_NHWC(32F, 2, 3), "a");
193
1
  const ccv_nnc_tensor_symbol_t b0 = ccv_nnc_tensor_symbol_new(graph, CPU_TENSOR_NHWC(32F, 2, 3), "b0");
194
1
  ccv_nnc_graph_exec_symbol_new(graph, CMD_SIGMOID_FORWARD(), TENSOR_SYMBOL_LIST(a), TENSOR_SYMBOL_LIST(b0), "sigmoid");
195
1
  const ccv_nnc_tensor_symbol_t label = ccv_nnc_tensor_symbol_new(graph, CPU_TENSOR_NHWC(32F, 2, 3), "label");
196
1
  const ccv_nnc_tensor_symbol_t loss0 = ccv_nnc_tensor_symbol_new(graph, ccv_nnc_tensor_auto, "loss0");
197
1
  ccv_nnc_graph_exec_symbol_new(graph, CMD_BINARY_CROSSENTROPY_FORWARD(), TENSOR_SYMBOL_LIST(b0, label), TENSOR_SYMBOL_LIST(loss0), "binary crossentropy");
198
1
  const ccv_nnc_tensor_symbol_t b1 = ccv_nnc_tensor_symbol_new(graph, CPU_TENSOR_NHWC(32F, 2, 3), "b1");
199
1
  const ccv_nnc_tensor_symbol_t loss1 = ccv_nnc_tensor_symbol_new(graph, ccv_nnc_tensor_auto, "loss1");
200
1
  ccv_nnc_graph_exec_symbol_new(graph, CMD_SIGMOID_BINARY_CROSSENTROPY_FORWARD(), TENSOR_SYMBOL_LIST(a, label), TENSOR_SYMBOL_LIST(loss1, b1), "sigmoid binary crossentropy");
201
1
  ccv_nnc_graph_exec_symbol_autogen(graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
202
1
  ccv_nnc_symbolic_graph_backward(graph, TENSOR_SYMBOL_LIST(loss0), TENSOR_SYMBOL_LIST(a), SYMBOLIC_GRAPH_SOURCES(graph), SYMBOLIC_GRAPH_DESTINATIONS(graph));
203
1
  const ccv_nnc_tensor_symbol_t dloss0 = ccv_nnc_tensor_symbol_for_backward(graph, loss0);
204
1
  const ccv_nnc_tensor_symbol_t da0 = ccv_nnc_tensor_symbol_for_backward(graph, a);
205
1
  ccv_nnc_symbolic_graph_backward(graph, TENSOR_SYMBOL_LIST(loss1), TENSOR_SYMBOL_LIST(a), SYMBOLIC_GRAPH_SOURCES(graph), SYMBOLIC_GRAPH_DESTINATIONS(graph));
206
1
  const ccv_nnc_tensor_symbol_t dloss1 = ccv_nnc_tensor_symbol_for_backward(graph, loss1);
207
1
  ccv_nnc_graph_exec_symbol_new(graph, CMD_SET_FORWARD(1), 0, 0, TENSOR_SYMBOL_LIST(dloss0, dloss1), "set 1");
208
1
  const ccv_nnc_tensor_symbol_t da1 = ccv_nnc_tensor_symbol_for_backward(graph, a);
209
1
  ccv_nnc_graph_exec_symbol_autogen(graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
210
1
  SYMBOLIC_GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
211
1
  ccv_nnc_graph_t* run_graph;
212
1
  ccv_nnc_tensor_arena_t* tensor_arena;
213
1
  ccv_nnc_graph_exec_arena_t* graph_exec_arena;
214
1
  ccv_nnc_symbolic_graph_compile(graph, ccv_nnc_default_compile_params,
215
1
    0, 0,
216
1
    TENSOR_SYMBOL_LIST(da0, da1, loss0, loss1),
217
1
    SYMBOLIC_GRAPH_SOURCES(graph), SYMBOLIC_GRAPH_DESTINATIONS(graph),
218
1
    &run_graph, &tensor_arena, &graph_exec_arena);
219
1
  ccv_nnc_tensor_t* const a_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, a);
220
1
  a_tensor->data.f32[0] = 10;
221
1
  a_tensor->data.f32[1] = -1;
222
1
  a_tensor->data.f32[2] = -5;
223
1
  a_tensor->data.f32[3] = 12;
224
1
  a_tensor->data.f32[4] = 4;
225
1
  a_tensor->data.f32[5] = 5;
226
1
  ccv_nnc_tensor_t* const label_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, label);
227
1
  label_tensor->data.f32[0] = 1;
228
1
  label_tensor->data.f32[1] = 0;
229
1
  label_tensor->data.f32[2] = 0;
230
1
  label_tensor->data.f32[3] = 1;
231
1
  label_tensor->data.f32[4] = 1;
232
1
  label_tensor->data.f32[5] = 0;
233
1
  ccv_nnc_graph_run(run_graph, 0, TRAVERSE_FULL, 0, 0);
234
1
  ccv_nnc_tensor_t* const da0_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, da0);
235
1
  ccv_nnc_tensor_t* const da1_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, da1);
236
1
  REQUIRE_TENSOR_EQ(da0_tensor, da1_tensor, "two tensors from combined op and separate ops should be equal");
237
1
  ccv_nnc_tensor_t* const loss0_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, loss0);
238
1
  ccv_nnc_tensor_t* const loss1_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, loss1);
239
1
  REQUIRE_TENSOR_EQ(loss0_tensor, loss1_tensor, "two tensors from combined op and separate ops should be equal");
240
1
  ccv_nnc_graph_free(run_graph);
241
1
  ccv_nnc_tensor_arena_free(tensor_arena);
242
1
  ccv_nnc_graph_exec_arena_free(graph_exec_arena);
243
1
  ccv_nnc_symbolic_graph_free(graph);
244
1
}
245
246
TEST_CASE("compare sigmoid + binary entropy v.s. sigmoid binary entropy command with pos_weight")
247
1
{
248
1
  ccv_nnc_symbolic_graph_t* const graph = ccv_nnc_symbolic_graph_new();
249
  // batch size = 2, dim = 3.
250
1
  const ccv_nnc_tensor_symbol_t a = ccv_nnc_tensor_symbol_new(graph, CPU_TENSOR_NHWC(32F, 2, 3), "a");
251
1
  const ccv_nnc_tensor_symbol_t b0 = ccv_nnc_tensor_symbol_new(graph, CPU_TENSOR_NHWC(32F, 2, 3), "b0");
252
1
  ccv_nnc_graph_exec_symbol_new(graph, CMD_SIGMOID_FORWARD(), TENSOR_SYMBOL_LIST(a), TENSOR_SYMBOL_LIST(b0), "sigmoid");
253
1
  const ccv_nnc_tensor_symbol_t label = ccv_nnc_tensor_symbol_new(graph, CPU_TENSOR_NHWC(32F, 2, 3), "label");
254
1
  const ccv_nnc_tensor_symbol_t loss0 = ccv_nnc_tensor_symbol_new(graph, ccv_nnc_tensor_auto, "loss0");
255
1
  const float pos_weight = 1.2;
256
1
  ccv_nnc_graph_exec_symbol_new(graph, CMD_BINARY_CROSSENTROPY_FORWARD(pos_weight), TENSOR_SYMBOL_LIST(b0, label), TENSOR_SYMBOL_LIST(loss0), "binary crossentropy");
257
1
  const ccv_nnc_tensor_symbol_t b1 = ccv_nnc_tensor_symbol_new(graph, CPU_TENSOR_NHWC(32F, 2, 3), "b1");
258
1
  const ccv_nnc_tensor_symbol_t loss1 = ccv_nnc_tensor_symbol_new(graph, ccv_nnc_tensor_auto, "loss1");
259
1
  ccv_nnc_graph_exec_symbol_new(graph, CMD_SIGMOID_BINARY_CROSSENTROPY_FORWARD(pos_weight), TENSOR_SYMBOL_LIST(a, label), TENSOR_SYMBOL_LIST(loss1, b1), "sigmoid binary crossentropy");
260
1
  ccv_nnc_graph_exec_symbol_autogen(graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
261
1
  ccv_nnc_symbolic_graph_backward(graph, TENSOR_SYMBOL_LIST(loss0), TENSOR_SYMBOL_LIST(a), SYMBOLIC_GRAPH_SOURCES(graph), SYMBOLIC_GRAPH_DESTINATIONS(graph));
262
1
  const ccv_nnc_tensor_symbol_t dloss0 = ccv_nnc_tensor_symbol_for_backward(graph, loss0);
263
1
  const ccv_nnc_tensor_symbol_t da0 = ccv_nnc_tensor_symbol_for_backward(graph, a);
264
1
  ccv_nnc_symbolic_graph_backward(graph, TENSOR_SYMBOL_LIST(loss1), TENSOR_SYMBOL_LIST(a), SYMBOLIC_GRAPH_SOURCES(graph), SYMBOLIC_GRAPH_DESTINATIONS(graph));
265
1
  const ccv_nnc_tensor_symbol_t dloss1 = ccv_nnc_tensor_symbol_for_backward(graph, loss1);
266
1
  ccv_nnc_graph_exec_symbol_new(graph, CMD_SET_FORWARD(1), 0, 0, TENSOR_SYMBOL_LIST(dloss0, dloss1), "set 1");
267
1
  const ccv_nnc_tensor_symbol_t da1 = ccv_nnc_tensor_symbol_for_backward(graph, a);
268
1
  ccv_nnc_graph_exec_symbol_autogen(graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
269
1
  SYMBOLIC_GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH);
270
1
  ccv_nnc_graph_t* run_graph;
271
1
  ccv_nnc_tensor_arena_t* tensor_arena;
272
1
  ccv_nnc_graph_exec_arena_t* graph_exec_arena;
273
1
  ccv_nnc_symbolic_graph_compile(graph, ccv_nnc_default_compile_params,
274
1
    0, 0,
275
1
    TENSOR_SYMBOL_LIST(da0, da1, loss0, loss1),
276
1
    SYMBOLIC_GRAPH_SOURCES(graph), SYMBOLIC_GRAPH_DESTINATIONS(graph),
277
1
    &run_graph, &tensor_arena, &graph_exec_arena);
278
1
  ccv_nnc_tensor_t* const a_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, a);
279
1
  a_tensor->data.f32[0] = 10;
280
1
  a_tensor->data.f32[1] = -1;
281
1
  a_tensor->data.f32[2] = -5;
282
1
  a_tensor->data.f32[3] = 12;
283
1
  a_tensor->data.f32[4] = 4;
284
1
  a_tensor->data.f32[5] = 5;
285
1
  ccv_nnc_tensor_t* const label_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, label);
286
1
  label_tensor->data.f32[0] = 1;
287
1
  label_tensor->data.f32[1] = 0;
288
1
  label_tensor->data.f32[2] = 0;
289
1
  label_tensor->data.f32[3] = 1;
290
1
  label_tensor->data.f32[4] = 1;
291
1
  label_tensor->data.f32[5] = 0;
292
1
  ccv_nnc_graph_run(run_graph, 0, TRAVERSE_FULL, 0, 0);
293
1
  ccv_nnc_tensor_t* const da0_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, da0);
294
1
  ccv_nnc_tensor_t* const da1_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, da1);
295
1
  REQUIRE_TENSOR_EQ(da0_tensor, da1_tensor, "two tensors from combined op and separate ops should be equal");
296
1
  ccv_nnc_tensor_t* const loss0_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, loss0);
297
1
  ccv_nnc_tensor_t* const loss1_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, loss1);
298
1
  REQUIRE_TENSOR_EQ(loss0_tensor, loss1_tensor, "two tensors from combined op and separate ops should be equal");
299
1
  ccv_nnc_graph_free(run_graph);
300
1
  ccv_nnc_tensor_arena_free(tensor_arena);
301
1
  ccv_nnc_graph_exec_arena_free(graph_exec_arena);
302
1
  ccv_nnc_symbolic_graph_free(graph);
303
1
}
304
305
#include "case_main.h"