/home/liu/actions-runner/_work/ccv/ccv/test/int/nnc/symbolic.graph.vgg.d.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 | | #include <inc/ccv_convnet_internal.h> |
8 | | |
9 | | TEST_SETUP() |
10 | | { |
11 | | ccv_nnc_init(); |
12 | | } |
13 | | |
14 | | static ccv_nnc_symbolic_graph_t* ccv_nnc_simple_symbolic_graph(ccv_convnet_t* convnet, ccv_nnc_tensor_t* input, ccv_nnc_tensor_t* output, ccv_nnc_graph_exec_symbol_t* source_symbol, ccv_nnc_graph_exec_symbol_t* dest_symbol, ccv_nnc_tensor_symbol_t* input_symbol_ref, ccv_nnc_tensor_symbol_t* output_symbol_ref, ccv_nnc_tensor_symbol_t* w_symbols, ccv_nnc_tensor_symbol_t* bias_symbols) |
15 | 1 | { |
16 | 1 | int i; |
17 | | // We only create the graph compute to the last fc layer. |
18 | 1 | ccv_nnc_symbolic_graph_t* symbolic_vgg = ccv_nnc_symbolic_graph_new(); |
19 | 1 | ccv_nnc_tensor_param_t input_info = input->info; |
20 | 1 | ccv_nnc_tensor_symbol_t input_symbol = ccv_nnc_tensor_symbol_new(symbolic_vgg, input->info, 0); |
21 | 1 | *input_symbol_ref = input_symbol; |
22 | 1 | ccv_nnc_tensor_symbol_t output_symbol = ccv_nnc_tensor_symbol_new(symbolic_vgg, output->info, 0); |
23 | 1 | *output_symbol_ref = output_symbol; |
24 | 1 | ccv_nnc_graph_exec_symbol_t previous_exec_symbol; |
25 | 22 | for (i = 0; i < convnet->count; i++21 ) |
26 | 21 | { |
27 | 21 | ccv_convnet_layer_t* layer = convnet->layers + i; |
28 | 21 | int rows, cols, partition; |
29 | 21 | ccv_convnet_make_output(layer, layer->input.matrix.rows, layer->input.matrix.cols, &rows, &cols, &partition); |
30 | 21 | ccv_nnc_tensor_param_t tensor_info = output->info; |
31 | 21 | ccv_nnc_tensor_symbol_t tensor_symbol = output_symbol; |
32 | 21 | if (i < convnet->count - 1) |
33 | 20 | { |
34 | 20 | if (layer->type == CCV_CONVNET_FULL_CONNECT) |
35 | 2 | tensor_info = CPU_TENSOR_NHWC(32F, rows * cols * partition); |
36 | 18 | else |
37 | 18 | tensor_info = CPU_TENSOR_NHWC(32F, rows, cols, (layer->type == CCV_CONVNET_CONVOLUTIONAL ? layer->net.convolutional.count : layer->input.matrix.channels)); |
38 | 20 | tensor_symbol = ccv_nnc_tensor_symbol_new(symbolic_vgg, tensor_info, 0); |
39 | 20 | } |
40 | 21 | ccv_nnc_graph_exec_symbol_t exec_symbol = {0}; |
41 | 21 | if (layer->type == CCV_CONVNET_CONVOLUTIONAL) |
42 | 13 | { |
43 | 13 | ccv_nnc_tensor_symbol_t w_symbol = ccv_nnc_tensor_symbol_new(symbolic_vgg, CPU_TENSOR_NHWC(32F, layer->net.convolutional.count, layer->net.convolutional.rows, layer->net.convolutional.cols, layer->net.convolutional.channels), 0); |
44 | 13 | w_symbols[i] = w_symbol; |
45 | 13 | ccv_nnc_tensor_symbol_t bias_symbol = ccv_nnc_tensor_symbol_new(symbolic_vgg, CPU_TENSOR_NHWC(32F, layer->net.convolutional.count), 0); |
46 | 13 | bias_symbols[i] = bias_symbol; |
47 | 13 | ccv_nnc_cmd_t cmd = CMD_CONVOLUTION_FORWARD(1, layer->net.convolutional.count, layer->net.convolutional.rows, layer->net.convolutional.cols, layer->net.convolutional.channels); |
48 | 13 | exec_symbol = ccv_nnc_graph_exec_symbol_new(symbolic_vgg, cmd, TENSOR_SYMBOL_LIST(input_symbol, w_symbol, bias_symbol), TENSOR_SYMBOL_LIST(tensor_symbol), 0); |
49 | 13 | } else if (8 layer->type == CCV_CONVNET_MAX_POOL8 ) { |
50 | 5 | ccv_nnc_cmd_t cmd = CMD_MAX_POOL_FORWARD(layer->net.pool.size, layer->net.pool.size); |
51 | 5 | exec_symbol = ccv_nnc_graph_exec_symbol_new(symbolic_vgg, cmd, TENSOR_SYMBOL_LIST(input_symbol), TENSOR_SYMBOL_LIST(tensor_symbol), 0); |
52 | 5 | } else if (3 layer->type == CCV_CONVNET_FULL_CONNECT3 ) { |
53 | 3 | ccv_nnc_tensor_symbol_t w_symbol = ccv_nnc_tensor_symbol_new(symbolic_vgg, CPU_TENSOR_NHWC(32F, layer->net.full_connect.count, layer->input.node.count), 0); |
54 | 3 | w_symbols[i] = w_symbol; |
55 | 3 | ccv_nnc_tensor_symbol_t bias_symbol = ccv_nnc_tensor_symbol_new(symbolic_vgg, CPU_TENSOR_NHWC(32F, layer->net.full_connect.count), 0); |
56 | 3 | bias_symbols[i] = bias_symbol; |
57 | 3 | ccv_nnc_cmd_t cmd = CMD_GEMM_FORWARD(NO_TRANSPOSE, TRANSPOSE(0, 1)); |
58 | | // If the input is not what I expected (array), reshape it. |
59 | 3 | if (input_info.dim[0] != ccv_nnc_tensor_count(input_info)) |
60 | 1 | input_symbol = ccv_nnc_tensor_symbol_alias_new(symbolic_vgg, input_symbol, ccv_nnc_no_ofs, DIM_ALLOC(1), CPU_TENSOR_NHWC(32F, ccv_nnc_tensor_count(input_info)), 0); |
61 | 3 | exec_symbol = ccv_nnc_graph_exec_symbol_new(symbolic_vgg, cmd, TENSOR_SYMBOL_LIST(input_symbol, w_symbol, bias_symbol), TENSOR_SYMBOL_LIST(tensor_symbol), 0); |
62 | 3 | } else { |
63 | 0 | assert("unreachable"); |
64 | 0 | } |
65 | 21 | if (i != 0) |
66 | 20 | ccv_nnc_graph_exec_symbol_concat(symbolic_vgg, previous_exec_symbol, exec_symbol); |
67 | 21 | previous_exec_symbol = exec_symbol; |
68 | 21 | if (i == 0) |
69 | 1 | *source_symbol = exec_symbol; |
70 | 21 | if (i < convnet->count - 1 && |
71 | 21 | (20 layer->type == CCV_CONVNET_CONVOLUTIONAL20 || layer->type == CCV_CONVNET_FULL_CONNECT7 )) |
72 | 15 | { |
73 | | // Create the ReLU layer. |
74 | 15 | ccv_nnc_cmd_t cmd = CMD_RELU_FORWARD(); |
75 | 15 | ccv_nnc_tensor_symbol_t next_symbol = ccv_nnc_tensor_symbol_new(symbolic_vgg, tensor_info, 0); |
76 | 15 | exec_symbol = ccv_nnc_graph_exec_symbol_new(symbolic_vgg, cmd, TENSOR_SYMBOL_LIST(tensor_symbol), TENSOR_SYMBOL_LIST(next_symbol), 0); |
77 | 15 | ccv_nnc_graph_exec_symbol_concat(symbolic_vgg, previous_exec_symbol, exec_symbol); |
78 | 15 | tensor_symbol = next_symbol; |
79 | 15 | previous_exec_symbol = exec_symbol; |
80 | 15 | } |
81 | 21 | if (i == convnet->count - 1) |
82 | 1 | *dest_symbol = exec_symbol; |
83 | | // This is the input of next layer. |
84 | 21 | input_symbol = tensor_symbol; |
85 | 21 | input_info = tensor_info; |
86 | 21 | } |
87 | 1 | return symbolic_vgg; |
88 | 1 | } |
89 | | |
90 | | #ifdef HAVE_LIBPNG |
91 | | TEST_CASE("run vgg-d graph from its symbolic representation") |
92 | 1 | { |
93 | 1 | ccv_convnet_t* convnet = ccv_convnet_read(0, "../../../samples/image-net-2012-vgg-d.sqlite3"); |
94 | 1 | ccv_dense_matrix_t* image = 0; |
95 | 1 | ccv_read("../../../samples/dex.png", &image, CCV_IO_ANY_FILE | CCV_IO_RGB_COLOR); |
96 | 1 | ccv_dense_matrix_t* input = 0; |
97 | 1 | ccv_convnet_input_formation(convnet->input, image, &input); |
98 | 1 | ccv_matrix_free(image); |
99 | 1 | ccv_dense_matrix_t* sliced = 0; |
100 | 1 | ccv_slice(input, (ccv_matrix_t**)&sliced, 0, (input->rows - 225) / 2, (input->cols - 225) / 2, 225, 225); |
101 | 1 | ccv_matrix_free(input); |
102 | 1 | ccv_dense_matrix_t* b = 0; |
103 | 1 | ccv_convnet_encode(convnet, &sliced, &b, 1); |
104 | 1 | ccv_nnc_tensor_t* c = ccv_nnc_tensor_new(0, CPU_TENSOR_NHWC(32F, 1000), 0); |
105 | 1 | ccv_nnc_tensor_symbol_t* w_symbols = ccmalloc(sizeof(ccv_nnc_tensor_symbol_t) * convnet->count); |
106 | 1 | ccv_nnc_tensor_symbol_t* bias_symbols = ccmalloc(sizeof(ccv_nnc_tensor_symbol_t) * convnet->count); |
107 | 1 | ccv_nnc_graph_exec_symbol_t source_symbol, dest_symbol; |
108 | 1 | ccv_nnc_tensor_symbol_t input_symbol, output_symbol; |
109 | 1 | ccv_nnc_symbolic_graph_t* graph = ccv_nnc_simple_symbolic_graph(convnet, (ccv_nnc_tensor_t*)sliced, c, &source_symbol, &dest_symbol, &input_symbol, &output_symbol, w_symbols, bias_symbols); |
110 | 1 | ccv_nnc_graph_t* run_graph = 0; |
111 | 1 | ccv_nnc_tensor_arena_t* tensor_arena = 0; |
112 | 1 | ccv_nnc_graph_exec_arena_t* graph_exec_arena = 0; |
113 | 1 | SYMBOLIC_GRAPH_GEN(graph, CCV_NNC_LONG_DOT_GRAPH); |
114 | 1 | ccv_nnc_symbolic_graph_compile(graph, ccv_nnc_default_compile_params, TENSOR_BIND_MAP(KV(input_symbol, (ccv_nnc_tensor_t*)sliced), KV(output_symbol, c)), 0, 0, GRAPH_EXEC_SYMBOL_LIST(source_symbol), GRAPH_EXEC_SYMBOL_LIST(dest_symbol), &run_graph, &tensor_arena, &graph_exec_arena); |
115 | 1 | GRAPH_GEN(run_graph, CCV_NNC_LONG_DOT_GRAPH); |
116 | 1 | REQUIRE(ccv_nnc_tensor_arena_size(tensor_arena) <= 471513504, "the allocated size should be smaller than what we previously got"); |
117 | 1 | int i; |
118 | 22 | for (i = 0; i < convnet->count; i++21 ) |
119 | 21 | { |
120 | 21 | ccv_convnet_layer_t* layer = convnet->layers + i; |
121 | 21 | if (layer->type == CCV_CONVNET_CONVOLUTIONAL) |
122 | 13 | { |
123 | 13 | ccv_nnc_tensor_t* w = ccv_nnc_tensor_from_symbol(tensor_arena, w_symbols[i]); |
124 | 13 | memcpy(w->data.f32, layer->w, layer->wnum * sizeof(float)); |
125 | 13 | ccv_nnc_tensor_t* bias = ccv_nnc_tensor_from_symbol(tensor_arena, bias_symbols[i]); |
126 | 13 | memcpy(bias->data.f32, layer->bias, layer->net.convolutional.count * sizeof(float)); |
127 | 13 | } else if (8 layer->type == CCV_CONVNET_FULL_CONNECT8 ) { |
128 | 3 | ccv_nnc_tensor_t* w = ccv_nnc_tensor_from_symbol(tensor_arena, w_symbols[i]); |
129 | 3 | memcpy(w->data.f32, layer->w, layer->wnum * sizeof(float)); |
130 | 3 | ccv_nnc_tensor_t* bias = ccv_nnc_tensor_from_symbol(tensor_arena, bias_symbols[i]); |
131 | 3 | memcpy(bias->data.f32, layer->bias, layer->net.full_connect.count * sizeof(float)); |
132 | 3 | } |
133 | 21 | } |
134 | 1 | ccv_nnc_graph_autotune(run_graph, 0, 0, GRAPH_EXEC_LIST(ccv_nnc_graph_exec_from_symbol(graph_exec_arena, source_symbol)), GRAPH_EXEC_LIST(ccv_nnc_graph_exec_from_symbol(graph_exec_arena, dest_symbol))); |
135 | | // Repopulate the weight. Since the weight tensor may be reused, need to repopulate every time run. |
136 | | // To avoid this, bind the weights directly or declare as const. |
137 | 22 | for (i = 0; i < convnet->count; i++21 ) |
138 | 21 | { |
139 | 21 | ccv_convnet_layer_t* layer = convnet->layers + i; |
140 | 21 | if (layer->type == CCV_CONVNET_CONVOLUTIONAL) |
141 | 13 | { |
142 | 13 | ccv_nnc_tensor_t* w = ccv_nnc_tensor_from_symbol(tensor_arena, w_symbols[i]); |
143 | 13 | memcpy(w->data.f32, layer->w, layer->wnum * sizeof(float)); |
144 | 13 | ccv_nnc_tensor_t* bias = ccv_nnc_tensor_from_symbol(tensor_arena, bias_symbols[i]); |
145 | 13 | memcpy(bias->data.f32, layer->bias, layer->net.convolutional.count * sizeof(float)); |
146 | 13 | } else if (8 layer->type == CCV_CONVNET_FULL_CONNECT8 ) { |
147 | 3 | ccv_nnc_tensor_t* w = ccv_nnc_tensor_from_symbol(tensor_arena, w_symbols[i]); |
148 | 3 | memcpy(w->data.f32, layer->w, layer->wnum * sizeof(float)); |
149 | 3 | ccv_nnc_tensor_t* bias = ccv_nnc_tensor_from_symbol(tensor_arena, bias_symbols[i]); |
150 | 3 | memcpy(bias->data.f32, layer->bias, layer->net.full_connect.count * sizeof(float)); |
151 | 3 | } |
152 | 21 | } |
153 | 1 | ccv_nnc_graph_run(run_graph, 0, GRAPH_EXEC_LIST(ccv_nnc_graph_exec_from_symbol(graph_exec_arena, source_symbol)), GRAPH_EXEC_LIST(ccv_nnc_graph_exec_from_symbol(graph_exec_arena, dest_symbol)), 0, 0); |
154 | 1 | REQUIRE_ARRAY_EQ_WITH_TOLERANCE(float, b->data.f32, c->data.f32, 1000, 1e-4, "output should be the same from convnet and from the symbolic graph"); |
155 | 1 | ccv_nnc_tensor_free(c); |
156 | 1 | ccv_matrix_free(sliced); |
157 | 1 | ccv_matrix_free(b); |
158 | 1 | ccv_nnc_symbolic_graph_free(graph); |
159 | 1 | ccv_nnc_graph_free(run_graph); |
160 | 1 | ccv_nnc_tensor_arena_free(tensor_arena); |
161 | 1 | ccv_nnc_graph_exec_arena_free(graph_exec_arena); |
162 | 1 | ccfree(w_symbols); |
163 | 1 | ccfree(bias_symbols); |
164 | 1 | ccv_convnet_free(convnet); |
165 | 1 | } |
166 | | #endif |
167 | | |
168 | | #include "case_main.h" |