/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" |