/home/liu/actions-runner/_work/ccv/ccv/test/unit/nnc/simplify.tests.c
Line | Count | Source (jump to first uncovered line) |
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("simplify graph (x + y) * (x + y)") |
14 | 1 | { |
15 | 1 | ccv_nnc_symbolic_graph_t* const symbolic_graph = ccv_nnc_symbolic_graph_new(); |
16 | 1 | ccv_nnc_tensor_symbol_t x = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "x"); |
17 | 1 | ccv_nnc_tensor_symbol_t y = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "y"); |
18 | 1 | ccv_nnc_tensor_symbol_t z1 = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "z1"); |
19 | 1 | ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWSUM_FORWARD(), TENSOR_SYMBOL_LIST(x, y), TENSOR_SYMBOL_LIST(z1), "sum1"); |
20 | 1 | ccv_nnc_tensor_symbol_t z2 = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "z2"); |
21 | 1 | ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWSUM_FORWARD(), TENSOR_SYMBOL_LIST(x, y), TENSOR_SYMBOL_LIST(z2), "sum2"); |
22 | 1 | ccv_nnc_tensor_symbol_t z = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "z"); |
23 | 1 | ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWPROD_FORWARD(), TENSOR_SYMBOL_LIST(z1, z2), TENSOR_SYMBOL_LIST(z), "prod"); |
24 | 1 | ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS); |
25 | 1 | ccv_nnc_symbolic_graph_simplify(symbolic_graph, |
26 | 1 | SYMBOLIC_GRAPH_PASSES(CCV_NNC_SIMPLIFY_COMMON_SUBEXPRESSION_ELIMINATION, |
27 | 1 | CCV_NNC_SIMPLIFY_DATA_TRANSFER_OPT, |
28 | 1 | CCV_NNC_SIMPLIFY_OPS_FUSION, |
29 | 1 | CCV_NNC_SIMPLIFY_GRAPH_PRUNING), |
30 | 1 | 0, 0, |
31 | 1 | TENSOR_SYMBOL_LIST(z), SYMBOLIC_GRAPH_SOURCES(symbolic_graph), SYMBOLIC_GRAPH_DESTINATIONS(symbolic_graph)); |
32 | 1 | ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS); |
33 | 1 | SYMBOLIC_GRAPH_GEN(symbolic_graph, CCV_NNC_LONG_DOT_GRAPH); |
34 | 1 | ccv_nnc_graph_t* graph = 0; |
35 | 1 | ccv_nnc_tensor_arena_t* tensor_arena = 0; |
36 | 1 | ccv_nnc_graph_exec_arena_t* graph_exec_arena = 0; |
37 | 1 | ccv_nnc_symbolic_graph_compile(symbolic_graph, ccv_nnc_default_compile_params, 0, 0, 0, 0, SYMBOLIC_GRAPH_SOURCES(symbolic_graph), SYMBOLIC_GRAPH_DESTINATIONS(symbolic_graph), &graph, &tensor_arena, &graph_exec_arena); |
38 | 1 | GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH); |
39 | 1 | ccv_nnc_tensor_t* const x_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, x); |
40 | 1 | x_tensor->data.f32[0] = 10; |
41 | 1 | ccv_nnc_tensor_t* const y_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, y); |
42 | 1 | y_tensor->data.f32[0] = 8; |
43 | 1 | ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0); |
44 | 1 | ccv_nnc_tensor_t* const z_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, z); |
45 | 1 | REQUIRE_EQ_WITH_TOLERANCE(z_tensor->data.f32[0], (10 + 8) * (10 + 8), 1e-5, "result should be equal"); |
46 | 1 | ccv_nnc_symbolic_graph_free(symbolic_graph); |
47 | 1 | ccv_nnc_graph_free(graph); |
48 | 1 | ccv_nnc_tensor_arena_free(tensor_arena); |
49 | 1 | ccv_nnc_graph_exec_arena_free(graph_exec_arena); |
50 | 1 | } |
51 | | |
52 | | TEST_CASE("simplify graph with data transfer") |
53 | 1 | { |
54 | 1 | ccv_nnc_symbolic_graph_t* const symbolic_graph = ccv_nnc_symbolic_graph_new(); |
55 | 1 | ccv_nnc_tensor_symbol_t x = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "x"); |
56 | 1 | ccv_nnc_tensor_symbol_t y = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "y"); |
57 | 1 | ccv_nnc_tensor_symbol_t a1 = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "a1"); |
58 | 1 | ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWSUM_FORWARD(), TENSOR_SYMBOL_LIST(x, y), TENSOR_SYMBOL_LIST(a1), "sum1"); |
59 | 1 | ccv_nnc_tensor_symbol_t z = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 2), "z"); |
60 | 1 | ccv_nnc_tensor_symbol_t z1 = ccv_nnc_tensor_symbol_alias_new(symbolic_graph, z, DIM_ALLOC(0), DIM_ALLOC(1), CPU_TENSOR_NHWC(32F, 1), "z1"); |
61 | 1 | ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_DATA_TRANSFER_FORWARD(), TENSOR_SYMBOL_LIST(a1), TENSOR_SYMBOL_LIST(z1), "dt1"); |
62 | 1 | ccv_nnc_tensor_symbol_t a2 = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "a2"); |
63 | 1 | ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_DATA_TRANSFER_BACKWARD(), TENSOR_SYMBOL_LIST(x, y), TENSOR_SYMBOL_LIST(a2), "dt2"); |
64 | 1 | ccv_nnc_tensor_symbol_t z2 = ccv_nnc_tensor_symbol_alias_new(symbolic_graph, z, DIM_ALLOC(1), DIM_ALLOC(1), CPU_TENSOR_NHWC(32F, 1), "z2"); |
65 | 1 | ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_DATA_TRANSFER_FORWARD(), TENSOR_SYMBOL_LIST(a2), TENSOR_SYMBOL_LIST(z2), "dt3"); |
66 | 1 | ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS); |
67 | 1 | ccv_nnc_symbolic_graph_simplify(symbolic_graph, |
68 | 1 | SYMBOLIC_GRAPH_PASSES(CCV_NNC_SIMPLIFY_COMMON_SUBEXPRESSION_ELIMINATION, |
69 | 1 | CCV_NNC_SIMPLIFY_DATA_TRANSFER_OPT, |
70 | 1 | CCV_NNC_SIMPLIFY_OPS_FUSION, |
71 | 1 | CCV_NNC_SIMPLIFY_GRAPH_PRUNING), |
72 | 1 | 0, 0, |
73 | 1 | TENSOR_SYMBOL_LIST(z), SYMBOLIC_GRAPH_SOURCES(symbolic_graph), SYMBOLIC_GRAPH_DESTINATIONS(symbolic_graph)); |
74 | 1 | ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS); |
75 | 1 | SYMBOLIC_GRAPH_GEN(symbolic_graph, CCV_NNC_LONG_DOT_GRAPH); |
76 | 1 | ccv_nnc_graph_t* graph = 0; |
77 | 1 | ccv_nnc_tensor_arena_t* tensor_arena = 0; |
78 | 1 | ccv_nnc_graph_exec_arena_t* graph_exec_arena = 0; |
79 | 1 | ccv_nnc_symbolic_graph_compile(symbolic_graph, ccv_nnc_default_compile_params, 0, 0, 0, 0, SYMBOLIC_GRAPH_SOURCES(symbolic_graph), SYMBOLIC_GRAPH_DESTINATIONS(symbolic_graph), &graph, &tensor_arena, &graph_exec_arena); |
80 | 1 | GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH); |
81 | 1 | ccv_nnc_tensor_t* const z2_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, z2); |
82 | 1 | z2_tensor->data.f32[0] = 1.2; |
83 | 1 | ccv_nnc_tensor_t* const y_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, y); |
84 | 1 | y_tensor->data.f32[0] = 8; |
85 | 1 | ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0); |
86 | 1 | ccv_nnc_tensor_t* const z_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, z); |
87 | 1 | REQUIRE_EQ_WITH_TOLERANCE(z_tensor->data.f32[0], 1.2 + 8, 1e-5, "result should be equal"); |
88 | 1 | REQUIRE_EQ_WITH_TOLERANCE(z_tensor->data.f32[1], 1.2, 1e-5, "result should be equal"); |
89 | 1 | ccv_nnc_symbolic_graph_free(symbolic_graph); |
90 | 1 | ccv_nnc_graph_free(graph); |
91 | 1 | ccv_nnc_tensor_arena_free(tensor_arena); |
92 | 1 | ccv_nnc_graph_exec_arena_free(graph_exec_arena); |
93 | 1 | } |
94 | | |
95 | | TEST_CASE("simplify graph with softmax + crossentropy") |
96 | 1 | { |
97 | 1 | ccv_nnc_symbolic_graph_t* const symbolic_graph = ccv_nnc_symbolic_graph_new(); |
98 | 1 | const ccv_nnc_tensor_symbol_t a = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 2, 3), "a"); |
99 | 1 | const ccv_nnc_tensor_symbol_t b0 = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 2, 3), "b0"); |
100 | 1 | ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_SOFTMAX_FORWARD(), TENSOR_SYMBOL_LIST(a), TENSOR_SYMBOL_LIST(b0), "softmax"); |
101 | 1 | const ccv_nnc_tensor_symbol_t label = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32S, 2), "label"); |
102 | 1 | const ccv_nnc_tensor_symbol_t loss0 = ccv_nnc_tensor_symbol_new(symbolic_graph, ccv_nnc_tensor_auto, "loss0"); |
103 | 1 | ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_CATEGORICAL_CROSSENTROPY_FORWARD(), TENSOR_SYMBOL_LIST(b0, label), TENSOR_SYMBOL_LIST(loss0), "categorical crossentropy"); |
104 | 1 | ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS); |
105 | 1 | ccv_nnc_symbolic_graph_backward(symbolic_graph, TENSOR_SYMBOL_LIST(loss0), TENSOR_SYMBOL_LIST(a), SYMBOLIC_GRAPH_SOURCES(symbolic_graph), SYMBOLIC_GRAPH_DESTINATIONS(symbolic_graph)); |
106 | 1 | const ccv_nnc_tensor_symbol_t dloss0 = ccv_nnc_tensor_symbol_for_backward(symbolic_graph, loss0); |
107 | 1 | const ccv_nnc_tensor_symbol_t da0 = ccv_nnc_tensor_symbol_for_backward(symbolic_graph, a); |
108 | 1 | ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_SET_FORWARD(1), 0, 0, TENSOR_SYMBOL_LIST(dloss0), "set 1"); |
109 | 1 | ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS); |
110 | 1 | ccv_nnc_symbolic_graph_simplify(symbolic_graph, |
111 | 1 | SYMBOLIC_GRAPH_PASSES(CCV_NNC_SIMPLIFY_COMMON_SUBEXPRESSION_ELIMINATION, |
112 | 1 | CCV_NNC_SIMPLIFY_DATA_TRANSFER_OPT, |
113 | 1 | CCV_NNC_SIMPLIFY_OPS_FUSION, |
114 | 1 | CCV_NNC_SIMPLIFY_GRAPH_PRUNING), |
115 | 1 | 0, 0, |
116 | 1 | TENSOR_SYMBOL_LIST(da0), SYMBOLIC_GRAPH_SOURCES(symbolic_graph), SYMBOLIC_GRAPH_DESTINATIONS(symbolic_graph)); |
117 | 1 | ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS); |
118 | 1 | SYMBOLIC_GRAPH_GEN(symbolic_graph, CCV_NNC_LONG_DOT_GRAPH); |
119 | 1 | ccv_nnc_graph_t* graph; |
120 | 1 | ccv_nnc_tensor_arena_t* tensor_arena; |
121 | 1 | ccv_nnc_graph_exec_arena_t* graph_exec_arena; |
122 | 1 | ccv_nnc_symbolic_graph_compile(symbolic_graph, ccv_nnc_default_compile_params, 0, 0, 0, 0, SYMBOLIC_GRAPH_SOURCES(symbolic_graph), SYMBOLIC_GRAPH_DESTINATIONS(symbolic_graph), &graph, &tensor_arena, &graph_exec_arena); |
123 | 1 | ccv_nnc_tensor_t* const a_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, a); |
124 | 1 | ccv_nnc_tensor_t* const a0_tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0); |
125 | 1 | a0_tensor->data.f32[0] = a_tensor->data.f32[0] = 10; |
126 | 1 | a0_tensor->data.f32[1] = a_tensor->data.f32[1] = -1; |
127 | 1 | a0_tensor->data.f32[2] = a_tensor->data.f32[2] = -5; |
128 | 1 | a0_tensor->data.f32[3] = a_tensor->data.f32[3] = 12; |
129 | 1 | a0_tensor->data.f32[4] = a_tensor->data.f32[4] = 4; |
130 | 1 | a0_tensor->data.f32[5] = a_tensor->data.f32[5] = 24; |
131 | 1 | ccv_nnc_tensor_t* const label0_tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32S, 2), 0); |
132 | 1 | ccv_nnc_tensor_t* const label_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, label); |
133 | 1 | label0_tensor->data.i32[0] = label_tensor->data.i32[0] = 2; |
134 | 1 | label0_tensor->data.i32[1] = label_tensor->data.i32[1] = 1; |
135 | 1 | ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0); |
136 | 1 | ccv_nnc_tensor_t* const loss0_tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2), 0); |
137 | 1 | ccv_nnc_tensor_t* const softmax_tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0); |
138 | 1 | ccv_nnc_cmd_exec(CMD_SOFTMAX_CROSSENTROPY_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_LIST(a0_tensor, label0_tensor), TENSOR_LIST(loss0_tensor, softmax_tensor), 0); |
139 | 1 | ccv_nnc_tensor_free(a0_tensor); |
140 | 1 | ccv_nnc_tensor_free(loss0_tensor); |
141 | 1 | ccv_nnc_tensor_t* const da1_tensor = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 2, 3), 0); |
142 | 1 | ccv_nnc_cmd_exec(CMD_SOFTMAX_CROSSENTROPY_BACKWARD(), ccv_nnc_no_hint, 0, TENSOR_LIST(0, 0, 0, label0_tensor, 0, softmax_tensor), TENSOR_LIST(da1_tensor), 0); |
143 | 1 | ccv_nnc_tensor_t* const da0_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, da0); |
144 | 1 | REQUIRE_TENSOR_EQ(da0_tensor, da1_tensor, "two tensors from combined op and separate ops should be equal"); |
145 | 1 | ccv_nnc_graph_free(graph); |
146 | 1 | ccv_nnc_tensor_arena_free(tensor_arena); |
147 | 1 | ccv_nnc_graph_exec_arena_free(graph_exec_arena); |
148 | 1 | ccv_nnc_symbolic_graph_free(symbolic_graph); |
149 | 1 | ccv_nnc_tensor_free(label0_tensor); |
150 | 1 | ccv_nnc_tensor_free(softmax_tensor); |
151 | 1 | ccv_nnc_tensor_free(da1_tensor); |
152 | 1 | } |
153 | | |
154 | | static int custom_case_of(ccv_nnc_tensor_t* const* const inputs, const int input_size, const void* const data) |
155 | 2 | { |
156 | 2 | assert(input_size == 1); |
157 | 2 | if (inputs[0]->data.f32[0] < 0) |
158 | 1 | return 0; |
159 | 1 | else if (inputs[0]->data.f32[0] < 2) |
160 | 1 | return 1; |
161 | 0 | return -1; |
162 | 2 | } |
163 | | |
164 | | TEST_CASE("simplify graph with case..of") |
165 | 1 | { |
166 | 1 | ccv_nnc_symbolic_graph_t* const symbolic_graph = ccv_nnc_symbolic_graph_new(); |
167 | 1 | ccv_nnc_tensor_symbol_t x = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "x"); |
168 | 1 | ccv_nnc_tensor_symbol_t y = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "y"); |
169 | 1 | ccv_nnc_tensor_symbol_t sum1 = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), 0); |
170 | 1 | ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWSUM_FORWARD(), TENSOR_SYMBOL_LIST(x, y), TENSOR_SYMBOL_LIST(sum1), "sum1"); |
171 | 1 | ccv_nnc_tensor_symbol_t z = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "z"); |
172 | 1 | ccv_nnc_tensor_symbol_t prod1 = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), 0); |
173 | 1 | ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWPROD_FORWARD(), TENSOR_SYMBOL_LIST(sum1, z), TENSOR_SYMBOL_LIST(prod1), "prod1"); |
174 | 1 | ccv_nnc_tensor_symbol_t sum2 = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), 0); |
175 | 1 | ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWSUM_FORWARD(), TENSOR_SYMBOL_LIST(x, y), TENSOR_SYMBOL_LIST(sum2), "sum2"); |
176 | 1 | ccv_nnc_tensor_symbol_t prod2 = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), 0); |
177 | 1 | ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWPROD_FORWARD(), TENSOR_SYMBOL_LIST(sum2, z), TENSOR_SYMBOL_LIST(prod2), "prod2"); |
178 | 1 | ccv_nnc_tensor_symbol_t q = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), 0); |
179 | 1 | ccv_nnc_graph_exec_symbol_t case_of = ccv_nnc_symbolic_graph_case_of_new(symbolic_graph, CCV_NNC_GRAPH_FORWARD, TENSOR_SYMBOL_LIST(x), TENSOR_SYMBOL_MAP(KV(prod1, q)), "case..of"); |
180 | 1 | ccv_nnc_symbolic_graph_t* const case_of_1 = ccv_nnc_symbolic_graph_new(); |
181 | 1 | ccv_nnc_tensor_symbol_t y1 = ccv_nnc_tensor_symbol_new(case_of_1, CPU_TENSOR_NHWC(32F, 1), "y1"); |
182 | 1 | ccv_nnc_symbolic_graph_set_case_of(symbolic_graph, case_of, case_of_1, 0, TENSOR_SYMBOL_MAP(KV(y1, q))); |
183 | 1 | ccv_nnc_graph_exec_symbol_new(case_of_1, CMD_EWSUM_FORWARD(), TENSOR_SYMBOL_LIST(sum1, prod1, prod2), TENSOR_SYMBOL_LIST(y1), 0); |
184 | 1 | ccv_nnc_graph_exec_symbol_autogen(case_of_1, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS); |
185 | 1 | ccv_nnc_symbolic_graph_t* const case_of_2 = ccv_nnc_symbolic_graph_new(); |
186 | 1 | ccv_nnc_tensor_symbol_t y2 = ccv_nnc_tensor_symbol_new(case_of_2, CPU_TENSOR_NHWC(32F, 1), "y2"); |
187 | 1 | ccv_nnc_symbolic_graph_set_case_of(symbolic_graph, case_of, case_of_2, 1, TENSOR_SYMBOL_MAP(KV(y2, q))); |
188 | 1 | ccv_nnc_graph_exec_symbol_new(case_of_2, CMD_EWPROD_FORWARD(), TENSOR_SYMBOL_LIST(prod2, sum2), TENSOR_SYMBOL_LIST(y2), 0); |
189 | 1 | ccv_nnc_graph_exec_symbol_autogen(case_of_2, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS); |
190 | 1 | ccv_nnc_symbolic_graph_set_case_of_expr(symbolic_graph, case_of, custom_case_of, 0); |
191 | 1 | ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS); |
192 | 1 | ccv_nnc_symbolic_graph_simplify(symbolic_graph, |
193 | 1 | SYMBOLIC_GRAPH_PASSES(CCV_NNC_SIMPLIFY_COMMON_SUBEXPRESSION_ELIMINATION, |
194 | 1 | CCV_NNC_SIMPLIFY_DATA_TRANSFER_OPT, |
195 | 1 | CCV_NNC_SIMPLIFY_OPS_FUSION, |
196 | 1 | CCV_NNC_SIMPLIFY_GRAPH_PRUNING), |
197 | 1 | 0, 0, |
198 | 1 | TENSOR_SYMBOL_LIST(q), SYMBOLIC_GRAPH_SOURCES(symbolic_graph), SYMBOLIC_GRAPH_DESTINATIONS(symbolic_graph)); |
199 | 1 | ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS); |
200 | 1 | SYMBOLIC_GRAPH_GEN(symbolic_graph, CCV_NNC_LONG_DOT_GRAPH); |
201 | 1 | ccv_nnc_graph_t* graph = 0; |
202 | 1 | ccv_nnc_tensor_arena_t* tensor_arena = 0; |
203 | 1 | ccv_nnc_graph_exec_arena_t* graph_exec_arena = 0; |
204 | 1 | ccv_nnc_symbolic_graph_compile(symbolic_graph, ccv_nnc_default_compile_params, 0, 0, 0, 0, SYMBOLIC_GRAPH_SOURCES(symbolic_graph), SYMBOLIC_GRAPH_DESTINATIONS(symbolic_graph), &graph, &tensor_arena, &graph_exec_arena); |
205 | 1 | GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH); |
206 | 1 | ccv_nnc_tensor_t* x_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, x); |
207 | 1 | ccv_nnc_tensor_t* y_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, y); |
208 | 1 | ccv_nnc_tensor_t* z_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, z); |
209 | 1 | x_tensor->data.f32[0] = -2; |
210 | 1 | y_tensor->data.f32[0] = 1.1; |
211 | 1 | z_tensor->data.f32[0] = 2.2; |
212 | 1 | ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0); |
213 | 1 | ccv_nnc_tensor_t* q_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, q); |
214 | 1 | REQUIRE_EQ_WITH_TOLERANCE(q_tensor->data.f32[0], (-2 + 1.1) + (-2 + 1.1) * 2.2 + (-2 + 1.1) * 2.2, 1e-5, "q should be equal"); |
215 | 1 | x_tensor->data.f32[0] = 1.5; |
216 | 1 | y_tensor->data.f32[0] = 1.1; |
217 | 1 | z_tensor->data.f32[0] = 2.2; |
218 | 1 | ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0); |
219 | 1 | q_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, q); |
220 | 1 | REQUIRE_EQ_WITH_TOLERANCE(q_tensor->data.f32[0], (1.5 + 1.1) * (1.5 + 1.1) * 2.2, 1e-5, "q should be equal"); |
221 | 1 | ccv_nnc_symbolic_graph_free(symbolic_graph); |
222 | 1 | ccv_nnc_graph_free(graph); |
223 | 1 | ccv_nnc_tensor_arena_free(tensor_arena); |
224 | 1 | ccv_nnc_graph_exec_arena_free(graph_exec_arena); |
225 | 1 | } |
226 | | |
227 | | static int while_5(ccv_nnc_tensor_t* const* const inputs, const int input_size, const void* const data) |
228 | 18 | { |
229 | 18 | return inputs[0]->data.i64[0] < 5; |
230 | 18 | } |
231 | | |
232 | | TEST_CASE("simplify graph with while, variant 1") |
233 | 1 | { |
234 | 1 | ccv_nnc_symbolic_graph_t* const symbolic_graph = ccv_nnc_symbolic_graph_new(); |
235 | 1 | ccv_nnc_symbolic_graph_t* const while_graph = ccv_nnc_symbolic_graph_new(); |
236 | 1 | ccv_nnc_tensor_symbol_t x = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 1), "x"); |
237 | 1 | ccv_nnc_tensor_symbol_t y = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 1), "y"); |
238 | 1 | ccv_nnc_tensor_symbol_t z1 = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 1), "z1"); |
239 | 1 | ccv_nnc_graph_exec_symbol_new(while_graph, CMD_EWPROD_FORWARD(), TENSOR_SYMBOL_LIST(x, y), TENSOR_SYMBOL_LIST(z1), 0); |
240 | 1 | ccv_nnc_tensor_symbol_t p = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 1), "p"); |
241 | 1 | ccv_nnc_graph_exec_symbol_new(while_graph, CMD_EWPROD_FORWARD(), TENSOR_SYMBOL_LIST(x, y), TENSOR_SYMBOL_LIST(p), 0); |
242 | 1 | ccv_nnc_tensor_symbol_t z2 = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 1), "z2"); |
243 | 1 | ccv_nnc_graph_exec_symbol_t sum = ccv_nnc_graph_exec_symbol_new(while_graph, CMD_EWSUM_FORWARD(), TENSOR_SYMBOL_LIST(z1, p), TENSOR_SYMBOL_LIST(z2), 0); |
244 | 1 | ccv_nnc_graph_exec_symbol_autogen(while_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS); |
245 | 1 | ccv_nnc_symbolic_graph_while(symbolic_graph, CCV_NNC_GRAPH_FORWARD, while_graph, "while"); |
246 | 1 | ccv_nnc_symbolic_graph_set_while_expr(while_graph, while_5, 0, TENSOR_SYMBOL_LIST(ccv_nnc_tensor_symbol_for_while_count(while_graph)), GRAPH_EXEC_SYMBOL_LIST(sum)); |
247 | 1 | ccv_nnc_symbolic_graph_set_carry_overs(while_graph, TENSOR_SYMBOL_MAP(KV(z2, x))); |
248 | 1 | ccv_nnc_tensor_symbol_t f = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "f"); |
249 | | // Use p here so the graph can be simplified by replacing p with z1. |
250 | 1 | ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWSUM_FORWARD(), TENSOR_SYMBOL_LIST(p, z2), TENSOR_SYMBOL_LIST(f), 0); |
251 | 1 | ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS); |
252 | 1 | ccv_nnc_symbolic_graph_simplify(while_graph, |
253 | 1 | SYMBOLIC_GRAPH_PASSES(CCV_NNC_SIMPLIFY_COMMON_SUBEXPRESSION_ELIMINATION, |
254 | 1 | CCV_NNC_SIMPLIFY_DATA_TRANSFER_OPT, |
255 | 1 | CCV_NNC_SIMPLIFY_OPS_FUSION, |
256 | 1 | CCV_NNC_SIMPLIFY_GRAPH_PRUNING), |
257 | 1 | 0, 0, |
258 | 1 | TENSOR_SYMBOL_LIST(z2), SYMBOLIC_GRAPH_SOURCES(while_graph), SYMBOLIC_GRAPH_DESTINATIONS(while_graph)); |
259 | 1 | ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS); |
260 | 1 | SYMBOLIC_GRAPH_GEN(symbolic_graph, CCV_NNC_LONG_DOT_GRAPH); |
261 | 1 | ccv_nnc_graph_t* graph = 0; |
262 | 1 | ccv_nnc_tensor_arena_t* tensor_arena = 0; |
263 | 1 | ccv_nnc_graph_exec_arena_t* graph_exec_arena = 0; |
264 | 1 | ccv_nnc_symbolic_graph_compile(symbolic_graph, ccv_nnc_default_compile_params, 0, 0, 0, 0, SYMBOLIC_GRAPH_SOURCES(symbolic_graph), SYMBOLIC_GRAPH_DESTINATIONS(symbolic_graph), &graph, &tensor_arena, &graph_exec_arena); |
265 | 1 | GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH); |
266 | 1 | ccv_nnc_tensor_t* const x_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, x); |
267 | 1 | x_tensor->data.f32[0] = 0.5; |
268 | 1 | ccv_nnc_tensor_t* const y_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, y); |
269 | 1 | y_tensor->data.f32[0] = 1.1; |
270 | 1 | ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0); |
271 | 1 | ccv_nnc_tensor_t* const f_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, f); |
272 | 1 | int i; |
273 | 1 | float r = 0.5; |
274 | 7 | for (i = 0; i < 6; i++6 ) |
275 | 6 | r = r * 1.1 * 2; |
276 | 1 | REQUIRE_EQ_WITH_TOLERANCE(f_tensor->data.f32[0], r + r * 0.5, 1e-5, "should be equal"); |
277 | 1 | ccv_nnc_symbolic_graph_free(symbolic_graph); |
278 | 1 | ccv_nnc_graph_free(graph); |
279 | 1 | ccv_nnc_tensor_arena_free(tensor_arena); |
280 | 1 | ccv_nnc_graph_exec_arena_free(graph_exec_arena); |
281 | 1 | } |
282 | | |
283 | | TEST_CASE("simplify graph with while, variant 2") |
284 | 1 | { |
285 | 1 | ccv_nnc_symbolic_graph_t* const symbolic_graph = ccv_nnc_symbolic_graph_new(); |
286 | 1 | ccv_nnc_symbolic_graph_t* const while_graph = ccv_nnc_symbolic_graph_new(); |
287 | 1 | ccv_nnc_tensor_symbol_t x = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 1), "x"); |
288 | 1 | ccv_nnc_tensor_symbol_t y = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 1), "y"); |
289 | 1 | ccv_nnc_tensor_symbol_t z1 = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 1), "z1"); |
290 | 1 | ccv_nnc_graph_exec_symbol_new(while_graph, CMD_EWPROD_FORWARD(), TENSOR_SYMBOL_LIST(x, y), TENSOR_SYMBOL_LIST(z1), 0); |
291 | 1 | ccv_nnc_tensor_symbol_t p = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 1), "p"); |
292 | 1 | ccv_nnc_graph_exec_symbol_new(while_graph, CMD_EWPROD_FORWARD(), TENSOR_SYMBOL_LIST(x, y), TENSOR_SYMBOL_LIST(p), 0); |
293 | 1 | ccv_nnc_tensor_symbol_t z2 = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 1), "z2"); |
294 | 1 | ccv_nnc_graph_exec_symbol_t sum = ccv_nnc_graph_exec_symbol_new(while_graph, CMD_EWSUM_FORWARD(), TENSOR_SYMBOL_LIST(z1, p), TENSOR_SYMBOL_LIST(z2), 0); |
295 | 1 | ccv_nnc_graph_exec_symbol_autogen(while_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS); |
296 | 1 | ccv_nnc_symbolic_graph_while(symbolic_graph, CCV_NNC_GRAPH_FORWARD, while_graph, "while"); |
297 | 1 | ccv_nnc_symbolic_graph_set_while_expr(while_graph, while_5, 0, TENSOR_SYMBOL_LIST(ccv_nnc_tensor_symbol_for_while_count(while_graph)), GRAPH_EXEC_SYMBOL_LIST(sum)); |
298 | 1 | ccv_nnc_symbolic_graph_set_carry_overs(while_graph, TENSOR_SYMBOL_MAP(KV(z2, x))); |
299 | 1 | ccv_nnc_tensor_symbol_t f = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "f"); |
300 | | // Use z1 here so the branch produces p will be eliminated. |
301 | 1 | ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWSUM_FORWARD(), TENSOR_SYMBOL_LIST(z1, z2), TENSOR_SYMBOL_LIST(f), 0); |
302 | 1 | ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS); |
303 | 1 | ccv_nnc_symbolic_graph_simplify(while_graph, |
304 | 1 | SYMBOLIC_GRAPH_PASSES(CCV_NNC_SIMPLIFY_COMMON_SUBEXPRESSION_ELIMINATION, |
305 | 1 | CCV_NNC_SIMPLIFY_DATA_TRANSFER_OPT, |
306 | 1 | CCV_NNC_SIMPLIFY_OPS_FUSION, |
307 | 1 | CCV_NNC_SIMPLIFY_GRAPH_PRUNING), |
308 | 1 | 0, 0, |
309 | 1 | TENSOR_SYMBOL_LIST(z2), SYMBOLIC_GRAPH_SOURCES(while_graph), SYMBOLIC_GRAPH_DESTINATIONS(while_graph)); |
310 | 1 | ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS); |
311 | 1 | SYMBOLIC_GRAPH_GEN(symbolic_graph, CCV_NNC_LONG_DOT_GRAPH); |
312 | 1 | ccv_nnc_graph_t* graph = 0; |
313 | 1 | ccv_nnc_tensor_arena_t* tensor_arena = 0; |
314 | 1 | ccv_nnc_graph_exec_arena_t* graph_exec_arena = 0; |
315 | 1 | ccv_nnc_symbolic_graph_compile(symbolic_graph, ccv_nnc_default_compile_params, 0, 0, 0, 0, SYMBOLIC_GRAPH_SOURCES(symbolic_graph), SYMBOLIC_GRAPH_DESTINATIONS(symbolic_graph), &graph, &tensor_arena, &graph_exec_arena); |
316 | 1 | GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH); |
317 | 1 | ccv_nnc_tensor_t* const x_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, x); |
318 | 1 | x_tensor->data.f32[0] = 0.5; |
319 | 1 | ccv_nnc_tensor_t* const y_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, y); |
320 | 1 | y_tensor->data.f32[0] = 1.1; |
321 | 1 | ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0); |
322 | 1 | ccv_nnc_tensor_t* const f_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, f); |
323 | 1 | int i; |
324 | 1 | float r = 0.5; |
325 | 7 | for (i = 0; i < 6; i++6 ) |
326 | 6 | r = r * 1.1 * 2; |
327 | 1 | REQUIRE_EQ_WITH_TOLERANCE(f_tensor->data.f32[0], r + r * 0.5, 1e-5, "should be equal"); |
328 | 1 | ccv_nnc_symbolic_graph_free(symbolic_graph); |
329 | 1 | ccv_nnc_graph_free(graph); |
330 | 1 | ccv_nnc_tensor_arena_free(tensor_arena); |
331 | 1 | ccv_nnc_graph_exec_arena_free(graph_exec_arena); |
332 | 1 | } |
333 | | |
334 | | TEST_CASE("simplify graph with while, variant 3") |
335 | 1 | { |
336 | 1 | ccv_nnc_symbolic_graph_t* const symbolic_graph = ccv_nnc_symbolic_graph_new(); |
337 | 1 | ccv_nnc_symbolic_graph_t* const while_graph = ccv_nnc_symbolic_graph_new(); |
338 | 1 | ccv_nnc_tensor_symbol_t x = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 1), "x"); |
339 | 1 | ccv_nnc_tensor_symbol_t y = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 1), "y"); |
340 | 1 | ccv_nnc_tensor_symbol_t z1 = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 1), "z1"); |
341 | 1 | ccv_nnc_graph_exec_symbol_new(while_graph, CMD_EWPROD_FORWARD(), TENSOR_SYMBOL_LIST(x, y), TENSOR_SYMBOL_LIST(z1), 0); |
342 | 1 | ccv_nnc_tensor_symbol_t p = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 1), "p"); |
343 | 1 | ccv_nnc_graph_exec_symbol_new(while_graph, CMD_EWPROD_FORWARD(), TENSOR_SYMBOL_LIST(x, y), TENSOR_SYMBOL_LIST(p), 0); |
344 | 1 | ccv_nnc_tensor_symbol_t z2 = ccv_nnc_tensor_symbol_new(while_graph, CPU_TENSOR_NHWC(32F, 1), "z2"); |
345 | 1 | ccv_nnc_graph_exec_symbol_t sum = ccv_nnc_graph_exec_symbol_new(while_graph, CMD_EWSUM_FORWARD(), TENSOR_SYMBOL_LIST(z1, p), TENSOR_SYMBOL_LIST(z2), 0); |
346 | 1 | ccv_nnc_graph_exec_symbol_autogen(while_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS); |
347 | 1 | ccv_nnc_symbolic_graph_while(symbolic_graph, CCV_NNC_GRAPH_FORWARD, while_graph, "while"); |
348 | 1 | ccv_nnc_symbolic_graph_set_while_expr(while_graph, while_5, 0, TENSOR_SYMBOL_LIST(ccv_nnc_tensor_symbol_for_while_count(while_graph)), GRAPH_EXEC_SYMBOL_LIST(sum)); |
349 | 1 | ccv_nnc_symbolic_graph_set_carry_overs(while_graph, TENSOR_SYMBOL_MAP(KV(z2, x))); |
350 | 1 | ccv_nnc_tensor_symbol_t f = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "f"); |
351 | | // Use both z1 and p so this graph cannot be simplified (due to current implementation limitation). |
352 | 1 | ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWSUM_FORWARD(), TENSOR_SYMBOL_LIST(z1, p, z2), TENSOR_SYMBOL_LIST(f), 0); |
353 | 1 | ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS); |
354 | 1 | ccv_nnc_symbolic_graph_simplify(while_graph, |
355 | 1 | SYMBOLIC_GRAPH_PASSES(CCV_NNC_SIMPLIFY_COMMON_SUBEXPRESSION_ELIMINATION, |
356 | 1 | CCV_NNC_SIMPLIFY_DATA_TRANSFER_OPT, |
357 | 1 | CCV_NNC_SIMPLIFY_OPS_FUSION, |
358 | 1 | CCV_NNC_SIMPLIFY_GRAPH_PRUNING), |
359 | 1 | 0, 0, |
360 | 1 | TENSOR_SYMBOL_LIST(z2), SYMBOLIC_GRAPH_SOURCES(while_graph), SYMBOLIC_GRAPH_DESTINATIONS(while_graph)); |
361 | 1 | ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS); |
362 | 1 | SYMBOLIC_GRAPH_GEN(symbolic_graph, CCV_NNC_LONG_DOT_GRAPH); |
363 | 1 | ccv_nnc_graph_t* graph = 0; |
364 | 1 | ccv_nnc_tensor_arena_t* tensor_arena = 0; |
365 | 1 | ccv_nnc_graph_exec_arena_t* graph_exec_arena = 0; |
366 | 1 | ccv_nnc_symbolic_graph_compile(symbolic_graph, ccv_nnc_default_compile_params, 0, 0, 0, 0, SYMBOLIC_GRAPH_SOURCES(symbolic_graph), SYMBOLIC_GRAPH_DESTINATIONS(symbolic_graph), &graph, &tensor_arena, &graph_exec_arena); |
367 | 1 | GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH); |
368 | 1 | ccv_nnc_tensor_t* const x_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, x); |
369 | 1 | x_tensor->data.f32[0] = 0.5; |
370 | 1 | ccv_nnc_tensor_t* const y_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, y); |
371 | 1 | y_tensor->data.f32[0] = 1.1; |
372 | 1 | ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0); |
373 | 1 | ccv_nnc_tensor_t* const f_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, f); |
374 | 1 | int i; |
375 | 1 | float r = 0.5; |
376 | 7 | for (i = 0; i < 6; i++6 ) |
377 | 6 | r = r * 1.1 * 2; |
378 | 1 | REQUIRE_EQ_WITH_TOLERANCE(f_tensor->data.f32[0], r + r * 0.5 + r * 0.5, 1e-5, "should be equal"); |
379 | 1 | ccv_nnc_symbolic_graph_free(symbolic_graph); |
380 | 1 | ccv_nnc_graph_free(graph); |
381 | 1 | ccv_nnc_tensor_arena_free(tensor_arena); |
382 | 1 | ccv_nnc_graph_exec_arena_free(graph_exec_arena); |
383 | 1 | } |
384 | | |
385 | | #include "case_main.h" |