/home/liu/actions-runner/_work/ccv/ccv/test/unit/nnc/custom.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 | | static int _ccv_nnc_cmd_custom_exec(const ccv_nnc_cmd_t cmd, const ccv_nnc_hint_t hint, const int flags, ccv_nnc_tensor_t* const* const inputs, const int input_size, ccv_nnc_tensor_t* const* const outputs, const int output_size, ccv_nnc_stream_context_t* const stream_context) |
15 | 3 | { |
16 | 3 | if (cmd.cmd == CCV_NNC_CUSTOM_FORWARD) |
17 | 2 | { |
18 | 2 | ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new(); |
19 | 2 | const ccv_nnc_tensor_variable_t x = ccv_nnc_tensor_variable_new(graph); |
20 | 2 | ccv_nnc_tensor_variable_set(graph, x, inputs[0]); |
21 | 2 | const ccv_nnc_tensor_variable_t z = ccv_nnc_tensor_variable_new(graph); |
22 | 2 | ccv_nnc_dynamic_graph_exec(graph, CMD_EWLOG_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x), TENSOR_VARIABLE_LIST(z), 0, 0); |
23 | 2 | const ccv_nnc_tensor_variable_t y = ccv_nnc_tensor_variable_new(graph); |
24 | 2 | ccv_nnc_tensor_variable_set(graph, y, outputs[0]); |
25 | 2 | ccv_nnc_dynamic_graph_exec(graph, CMD_EWLOG_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(z), TENSOR_VARIABLE_LIST(y), 0, 0); |
26 | 2 | ccv_nnc_dynamic_graph_free(graph); |
27 | 2 | } else { |
28 | 1 | ccv_nnc_dynamic_graph_t* const graph = ccv_nnc_dynamic_graph_new(); |
29 | 1 | const ccv_nnc_tensor_variable_t x = ccv_nnc_tensor_variable_new(graph); |
30 | 1 | ccv_nnc_tensor_variable_set(graph, x, inputs[1]); |
31 | 1 | const ccv_nnc_tensor_variable_t z = ccv_nnc_tensor_variable_new(graph); |
32 | 1 | ccv_nnc_dynamic_graph_exec(graph, CMD_EWLOG_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(x), TENSOR_VARIABLE_LIST(z), 0, 0); |
33 | 1 | const ccv_nnc_tensor_variable_t y = ccv_nnc_tensor_variable_new(graph); |
34 | 1 | ccv_nnc_tensor_variable_set(graph, y, inputs[2]); |
35 | 1 | ccv_nnc_dynamic_graph_exec(graph, CMD_EWLOG_FORWARD(), ccv_nnc_no_hint, 0, TENSOR_VARIABLE_LIST(z), TENSOR_VARIABLE_LIST(y), 0, 0); |
36 | 1 | const ccv_nnc_tensor_variable_t dy = ccv_nnc_tensor_variable_new(graph); |
37 | 1 | ccv_nnc_tensor_variable_set(graph, dy, inputs[0]); |
38 | 1 | const ccv_nnc_tensor_variable_t dx = ccv_nnc_tensor_variable_new(graph); |
39 | 1 | ccv_nnc_tensor_variable_set(graph, dx, outputs[0]); |
40 | 1 | ccv_nnc_dynamic_graph_backward(graph, TENSOR_VARIABLE_LIST(y), &dy, TENSOR_VARIABLE_LIST(x), TENSOR_VARIABLE_LIST(dx), 0); |
41 | 1 | ccv_nnc_dynamic_graph_free(graph); |
42 | 1 | } |
43 | 3 | return CCV_NNC_EXEC_SUCCESS; |
44 | 3 | } |
45 | | |
46 | | static ccv_nnc_cmd_vtab_t _custom_isa = { |
47 | | .exec = _ccv_nnc_cmd_custom_exec, |
48 | | }; |
49 | | |
50 | | TEST_CASE("custom forward operation with dynamic graph") |
51 | 1 | { |
52 | 1 | const ccv_nnc_cmd_t cmd = ccv_nnc_cmd(CCV_NNC_CUSTOM_FORWARD, &_custom_isa, (ccv_nnc_cmd_param_t){}, 0); |
53 | 1 | ccv_nnc_symbolic_graph_t* const symbolic_graph = ccv_nnc_symbolic_graph_new(); |
54 | 1 | const ccv_nnc_tensor_symbol_t x = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "x"); |
55 | 1 | const ccv_nnc_tensor_symbol_t y = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "y"); |
56 | 1 | ccv_nnc_graph_exec_symbol_new(symbolic_graph, cmd, TENSOR_SYMBOL_LIST(x), TENSOR_SYMBOL_LIST(y), "custom"); |
57 | 1 | ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS | CCV_NNC_AUTOGEN_ALL_EXECS); |
58 | 1 | ccv_nnc_graph_t* graph; |
59 | 1 | ccv_nnc_tensor_arena_t* tensor_arena; |
60 | 1 | ccv_nnc_graph_exec_arena_t* graph_exec_arena; |
61 | 1 | ccv_nnc_symbolic_graph_compile(symbolic_graph, ccv_nnc_default_compile_params, 0, 0, |
62 | 1 | TENSOR_SYMBOL_LIST(y), |
63 | 1 | SYMBOLIC_GRAPH_SOURCES(symbolic_graph), SYMBOLIC_GRAPH_DESTINATIONS(symbolic_graph), |
64 | 1 | &graph, &tensor_arena, &graph_exec_arena); |
65 | 1 | ccv_nnc_symbolic_graph_free(symbolic_graph); |
66 | 1 | ccv_nnc_tensor_t* const x_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, x); |
67 | 1 | x_tensor->data.f32[0] = 10; |
68 | 1 | ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0); |
69 | 1 | ccv_nnc_tensor_t* const y_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, y); |
70 | 1 | REQUIRE_EQ_WITH_TOLERANCE(y_tensor->data.f32[0], log(log(10)), 1e-5, "computed result should be identical"); |
71 | 1 | ccv_nnc_graph_free(graph); |
72 | 1 | ccv_nnc_tensor_arena_free(tensor_arena); |
73 | 1 | ccv_nnc_graph_exec_arena_free(graph_exec_arena); |
74 | 1 | } |
75 | | |
76 | | TEST_CASE("custom backward operation with dynamic graph") |
77 | 1 | { |
78 | 1 | const ccv_nnc_cmd_t cmd = ccv_nnc_cmd(CCV_NNC_CUSTOM_FORWARD, &_custom_isa, (ccv_nnc_cmd_param_t){}, 0); |
79 | 1 | ccv_nnc_symbolic_graph_t* const symbolic_graph = ccv_nnc_symbolic_graph_new(); |
80 | 1 | const ccv_nnc_tensor_symbol_t x = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "x"); |
81 | 1 | const ccv_nnc_tensor_symbol_t y = ccv_nnc_tensor_symbol_new(symbolic_graph, CPU_TENSOR_NHWC(32F, 1), "y"); |
82 | 1 | ccv_nnc_graph_exec_symbol_new(symbolic_graph, cmd, TENSOR_SYMBOL_LIST(x), TENSOR_SYMBOL_LIST(y), "custom"); |
83 | 1 | ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS | CCV_NNC_AUTOGEN_ALL_EXECS); |
84 | 1 | ccv_nnc_symbolic_graph_backward(symbolic_graph, TENSOR_SYMBOL_LIST(y), TENSOR_SYMBOL_LIST(x), SYMBOLIC_GRAPH_SOURCES(symbolic_graph), SYMBOLIC_GRAPH_DESTINATIONS(symbolic_graph)); |
85 | 1 | const ccv_nnc_tensor_symbol_t dy = ccv_nnc_tensor_symbol_for_backward(symbolic_graph, y); |
86 | 1 | ccv_nnc_graph_exec_symbol_new(symbolic_graph, CMD_SET_FORWARD(1), TENSOR_SYMBOL_LIST(), TENSOR_SYMBOL_LIST(dy), "set"); |
87 | 1 | ccv_nnc_graph_exec_symbol_autogen(symbolic_graph, 0, 0, CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS | CCV_NNC_AUTOGEN_ALL_EXECS); |
88 | 1 | const ccv_nnc_tensor_symbol_t dx = ccv_nnc_tensor_symbol_for_backward(symbolic_graph, x); |
89 | 1 | ccv_nnc_graph_t* graph; |
90 | 1 | ccv_nnc_tensor_arena_t* tensor_arena; |
91 | 1 | ccv_nnc_graph_exec_arena_t* graph_exec_arena; |
92 | 1 | ccv_nnc_symbolic_graph_compile(symbolic_graph, ccv_nnc_default_compile_params, 0, 0, |
93 | 1 | TENSOR_SYMBOL_LIST(dx), |
94 | 1 | SYMBOLIC_GRAPH_SOURCES(symbolic_graph), SYMBOLIC_GRAPH_DESTINATIONS(symbolic_graph), |
95 | 1 | &graph, &tensor_arena, &graph_exec_arena); |
96 | 1 | ccv_nnc_symbolic_graph_free(symbolic_graph); |
97 | 1 | ccv_nnc_tensor_t* const x_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, x); |
98 | 1 | x_tensor->data.f32[0] = 10; |
99 | 1 | ccv_nnc_graph_run(graph, 0, TRAVERSE_FULL, 0, 0); |
100 | 1 | ccv_nnc_tensor_t* const dx_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, dx); |
101 | 1 | REQUIRE_EQ_WITH_TOLERANCE(dx_tensor->data.f32[0], 1. / (log(10) * 10), 1e-5, "computed result should be identical"); |
102 | 1 | ccv_nnc_graph_free(graph); |
103 | 1 | ccv_nnc_tensor_arena_free(tensor_arena); |
104 | 1 | ccv_nnc_graph_exec_arena_free(graph_exec_arena); |
105 | 1 | } |
106 | | |
107 | | #include "case_main.h" |