/home/liu/actions-runner/_work/ccv/ccv/test/unit/nnc/parallel.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("tensor symbol copy map grows dynamically on set copy") |
14 | 1 | { |
15 | 1 | ccv_nnc_symbolic_graph_t* const symbolic_graph = ccv_nnc_symbolic_graph_new(); |
16 | 1 | const ccv_nnc_tensor_symbol_t a = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "a"); |
17 | 1 | REQUIRE_EQ(ccv_nnc_tensor_symbol_copy(symbolic_graph, a, 1).d, CCV_NNC_NO_TENSOR_SYMBOL, "copy lookup should be empty before set_copy"); |
18 | 1 | const ccv_nnc_tensor_symbol_t a_copy = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "a_copy"); |
19 | 1 | ccv_nnc_tensor_symbol_set_copy(symbolic_graph, a, 1, a_copy); |
20 | 1 | REQUIRE_EQ(ccv_nnc_tensor_symbol_copy(symbolic_graph, a, 1).d, a_copy.d, "set_copy should allocate the copy map when missing"); |
21 | 1 | const ccv_nnc_tensor_symbol_t b = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "b"); |
22 | 1 | REQUIRE_EQ(ccv_nnc_tensor_symbol_copy(symbolic_graph, b, 1).d, CCV_NNC_NO_TENSOR_SYMBOL, "copy lookup should tolerate symbols outside the current map"); |
23 | 1 | const ccv_nnc_tensor_symbol_t b_copy = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "b_copy"); |
24 | 1 | ccv_nnc_tensor_symbol_set_copy(symbolic_graph, b, 1, b_copy); |
25 | 1 | REQUIRE_EQ(ccv_nnc_tensor_symbol_copy(symbolic_graph, b, 1).d, b_copy.d, "set_copy should grow rows for later canonical symbols"); |
26 | 1 | const ccv_nnc_tensor_symbol_t c = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "c"); |
27 | 1 | const ccv_nnc_tensor_symbol_t c_copy = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "c_copy"); |
28 | 1 | ccv_nnc_tensor_symbol_set_copy(symbolic_graph, c, 2, c_copy); |
29 | 1 | REQUIRE_EQ(ccv_nnc_tensor_symbol_copy(symbolic_graph, c, 2).d, c_copy.d, "set_copy should grow rank count when no exec copy map exists"); |
30 | 1 | REQUIRE_EQ(ccv_nnc_tensor_symbol_copy(symbolic_graph, a, 1).d, a_copy.d, "rank growth should preserve existing copy entries"); |
31 | 1 | REQUIRE_EQ(ccv_nnc_tensor_symbol_copy(symbolic_graph, a, 2).d, CCV_NNC_NO_TENSOR_SYMBOL, "new rank entries should default to no copy"); |
32 | 1 | ccv_nnc_tensor_symbol_set_copy(symbolic_graph, a, 1, a_copy); |
33 | 1 | REQUIRE_EQ(ccv_nnc_tensor_symbol_copy(symbolic_graph, c, 2).d, c_copy.d, "setting a smaller rank should not shrink existing rank entries"); |
34 | 1 | ccv_nnc_tensor_symbol_set_copy(symbolic_graph, b, 1, NO_TENSOR_SYMBOL); |
35 | 1 | REQUIRE_EQ(ccv_nnc_tensor_symbol_copy(symbolic_graph, b, 1).d, CCV_NNC_NO_TENSOR_SYMBOL, "set_copy should clear an existing copy entry"); |
36 | 1 | ccv_nnc_symbolic_graph_free(symbolic_graph); |
37 | 1 | } |
38 | | |
39 | | TEST_CASE("schedule a simple graph for parallel execution") |
40 | 1 | { |
41 | 1 | ccv_nnc_symbolic_graph_t* const symbolic_graph = ccv_nnc_symbolic_graph_new(); |
42 | 1 | const ccv_nnc_tensor_symbol_t x = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "x"); |
43 | 1 | const ccv_nnc_tensor_symbol_t y = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "y"); |
44 | 1 | const ccv_nnc_tensor_symbol_t z = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "z"); |
45 | 1 | ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWPROD_FORWARD(), TENSOR_SYMBOL_LIST(x, y), TENSOR_SYMBOL_LIST(z), "mul"); |
46 | 1 | const ccv_nnc_tensor_symbol_t a = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "a"); |
47 | 1 | const ccv_nnc_tensor_symbol_t b = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "b"); |
48 | 1 | const ccv_nnc_tensor_symbol_t c = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "c"); |
49 | 1 | ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWSUM_FORWARD(), TENSOR_SYMBOL_LIST(a, b), TENSOR_SYMBOL_LIST(c), "sum"); |
50 | 1 | const ccv_nnc_tensor_symbol_t d = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "d"); |
51 | 1 | ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWDIV_FORWARD(), TENSOR_SYMBOL_LIST(z, c), TENSOR_SYMBOL_LIST(d), "div"); |
52 | 1 | const ccv_nnc_tensor_symbol_t d0 = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "d0"); |
53 | 1 | ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWLOG_FORWARD(), TENSOR_SYMBOL_LIST(d), TENSOR_SYMBOL_LIST(d0), "log"); |
54 | 1 | const ccv_nnc_tensor_symbol_t d1 = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "d1"); |
55 | 1 | ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWEXP_FORWARD(), TENSOR_SYMBOL_LIST(d), TENSOR_SYMBOL_LIST(d1), "exp"); |
56 | 1 | const ccv_nnc_tensor_symbol_t d2 = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "d2"); |
57 | 1 | ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_EWSUM_FORWARD(), TENSOR_SYMBOL_LIST(d0, d1), TENSOR_SYMBOL_LIST(d2), "sum1"); |
58 | 1 | ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS); |
59 | 1 | SYMBOLIC_GRAPH_GEN(symbolic_graph, CCV_NNC_LONG_DOT_GRAPH); |
60 | 1 | ccv_nnc_graph_t* graph; |
61 | 1 | ccv_nnc_tensor_arena_t* tensor_arena; |
62 | 1 | ccv_nnc_graph_exec_arena_t* graph_exec_arena; |
63 | 1 | ccv_nnc_symbolic_graph_compile(symbolic_graph, ccv_nnc_default_compile_params, |
64 | 1 | 0, 0, |
65 | 1 | TENSOR_SYMBOL_LIST(d2), |
66 | 1 | SYMBOLIC_GRAPH_SOURCES(symbolic_graph), SYMBOLIC_GRAPH_DESTINATIONS(symbolic_graph), |
67 | 1 | &graph, &tensor_arena, &graph_exec_arena); |
68 | 1 | ccv_nnc_graph_set_default_static_schedule(graph, CCV_STREAM_CONTEXT_CPU, 0); |
69 | 1 | GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH); |
70 | 1 | ccv_nnc_tensor_t* const x_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, x); |
71 | 1 | x_tensor->data.f32[0] = 2; |
72 | 1 | ccv_nnc_tensor_t* const y_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, y); |
73 | 1 | y_tensor->data.f32[0] = 0.21; |
74 | 1 | ccv_nnc_tensor_t* const a_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, a); |
75 | 1 | a_tensor->data.f32[0] = 2.2; |
76 | 1 | ccv_nnc_tensor_t* const b_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, b); |
77 | 1 | b_tensor->data.f32[0] = 3.2; |
78 | 1 | ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0); |
79 | 1 | ccv_nnc_tensor_t* const d2_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, d2); |
80 | 1 | const float dv = 2 * 0.21 / (2.2 + 3.2); |
81 | 1 | REQUIRE_EQ_WITH_TOLERANCE(d2_tensor->data.f32[0], logf(dv) + expf(dv), 1e-5, "result should be equal"); |
82 | 1 | ccv_nnc_symbolic_graph_free(symbolic_graph); |
83 | 1 | ccv_nnc_graph_free(graph); |
84 | 1 | ccv_nnc_tensor_arena_free(tensor_arena); |
85 | 1 | ccv_nnc_graph_exec_arena_free(graph_exec_arena); |
86 | 1 | } |
87 | | |
88 | | TEST_CASE("schedule symbolic graph to data parallel") |
89 | 1 | { |
90 | 1 | ccv_nnc_symbolic_graph_t* const symbolic_graph = ccv_nnc_symbolic_graph_new(); |
91 | 1 | const ccv_nnc_tensor_symbol_t x = ccv_nnc_tensor_symbol_new(symbolic_graph, GPU_TENSOR_NHWC(000, 32F, 16, 32, 32, 3), 0); |
92 | 1 | const ccv_nnc_tensor_symbol_t w1 = ccv_nnc_tensor_symbol_new(symbolic_graph, GPU_TENSOR_NHWC(000, 32F, 8, 5, 5, 3), 0); |
93 | 1 | const ccv_nnc_tensor_symbol_t bias1 = ccv_nnc_tensor_symbol_new(symbolic_graph, GPU_TENSOR_NHWC(000, 32F, 8), 0); |
94 | 1 | const ccv_nnc_tensor_symbol_t y1 = ccv_nnc_tensor_symbol_new(symbolic_graph, GPU_TENSOR_NHWC(000, 32F, 16, 32, 32, 8), 0); |
95 | 1 | const ccv_nnc_graph_exec_symbol_t conv1 = ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_CONVOLUTION_FORWARD(1, 8, 5, 5, 3), TENSOR_SYMBOL_LIST(x, w1, bias1), TENSOR_SYMBOL_LIST(y1), "conv1"); |
96 | 1 | ccv_nnc_graph_exec_symbol_set_hint(symbolic_graph, conv1, HINT((1, 1), (2, 2))); |
97 | 1 | const ccv_nnc_tensor_symbol_t y2 = ccv_nnc_tensor_symbol_new(symbolic_graph, GPU_TENSOR_NHWC(000, 32F, 16, 16, 16, 8), 0); |
98 | 1 | const ccv_nnc_graph_exec_symbol_t avg2 = ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_AVERAGE_POOL_FORWARD(2, 2), TENSOR_SYMBOL_LIST(y1), TENSOR_SYMBOL_LIST(y2), "avg2"); |
99 | 1 | ccv_nnc_graph_exec_symbol_set_hint(symbolic_graph, avg2, HINT((2, 2))); |
100 | 1 | const ccv_nnc_tensor_symbol_t w3 = ccv_nnc_tensor_symbol_new(symbolic_graph, GPU_TENSOR_NHWC(000, 32F, 8, 5, 5, 8), 0); |
101 | 1 | const ccv_nnc_tensor_symbol_t bias3 = ccv_nnc_tensor_symbol_new(symbolic_graph, GPU_TENSOR_NHWC(000, 32F, 8), 0); |
102 | 1 | const ccv_nnc_tensor_symbol_t y3 = ccv_nnc_tensor_symbol_new(symbolic_graph, GPU_TENSOR_NHWC(000, 32F, 16, 8, 8, 8), 0); |
103 | 1 | const ccv_nnc_graph_exec_symbol_t conv3 = ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_CONVOLUTION_FORWARD(1, 8, 5, 5, 3), TENSOR_SYMBOL_LIST(y2, w3, bias3), TENSOR_SYMBOL_LIST(y3), "conv3"); |
104 | 1 | ccv_nnc_graph_exec_symbol_set_hint(symbolic_graph, conv3, HINT((2, 2), (2, 2))); |
105 | 1 | const ccv_nnc_tensor_symbol_t y4 = ccv_nnc_tensor_symbol_new(symbolic_graph, GPU_TENSOR_NHWC(000, 32F, 16, 1, 1, 8), 0); |
106 | 1 | ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_AVERAGE_POOL_FORWARD(8, 8), TENSOR_SYMBOL_LIST(y3), TENSOR_SYMBOL_LIST(y4), "avg4"); |
107 | 1 | const ccv_nnc_tensor_symbol_t label = ccv_nnc_tensor_symbol_new(symbolic_graph, GPU_TENSOR_NHWC(000, 32F, 16), "label"); |
108 | 1 | const ccv_nnc_tensor_symbol_t y5 = ccv_nnc_tensor_symbol_new(symbolic_graph, GPU_TENSOR_NHWC(000, 32F, 16, 1, 1, 8), "y5"); |
109 | 1 | const ccv_nnc_tensor_symbol_t loss = ccv_nnc_tensor_symbol_new(symbolic_graph, ccv_nnc_tensor_auto, "loss"); |
110 | 1 | ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_SOFTMAX_CROSSENTROPY_FORWARD(), TENSOR_SYMBOL_LIST(y4, label), TENSOR_SYMBOL_LIST(loss, y5), "softmax crossentropy"); |
111 | 1 | ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS); |
112 | 1 | ccv_nnc_tensor_symbol_t updated_params[4]; |
113 | 1 | ccv_nnc_tensor_symbol_t gradients[4]; |
114 | 1 | const int saved_aux_size = ccv_nnc_minimizer_saved_aux_size(CMD_SGD_FORWARD(0, 0.001, 1, 0.99, 0.9, 0.9)); |
115 | 1 | ccv_nnc_tensor_symbol_map_t saved_aux[saved_aux_size * 4]; |
116 | 1 | ccv_nnc_graph_exec_symbol_t updated_execs[4]; |
117 | 1 | ccv_nnc_symbolic_graph_minimize(symbolic_graph, CMD_SGD_FORWARD(0, 0.001, 1, 0.99, 0.9, 0.9), TENSOR_SYMBOL_LIST(loss), TENSOR_SYMBOL_LIST(w1, bias1, w3, bias3), 0, 0, SYMBOLIC_GRAPH_SOURCES(symbolic_graph), SYMBOLIC_GRAPH_DESTINATIONS(symbolic_graph), gradients, updated_params, saved_aux, updated_execs); |
118 | 1 | ccv_nnc_symbolic_graph_data_parallel(symbolic_graph, 2, TENSOR_SYMBOL_LIST(w1, bias1, w3, bias3), 0, 0, 0, gradients, 4, 0, CCV_NNC_PARALLEL_REDUCE_OP_SUM, SYMBOLIC_GRAPH_SOURCES(symbolic_graph), updated_execs, 4); |
119 | 1 | SYMBOLIC_GRAPH_GEN(symbolic_graph, CCV_NNC_LONG_DOT_GRAPH); |
120 | 1 | ccv_nnc_symbolic_graph_free(symbolic_graph); |
121 | 1 | } |
122 | | |
123 | | #include "case_main.h" |