Bug Summary

File:nnc/ccv_cnnp_model.c
Warning:line 2507, column 1
Assigned value is garbage or undefined

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name ccv_cnnp_model.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -target-feature +sse2 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/home/liu/actions-runner/_work/ccv/ccv/lib/nnc -fcoverage-compilation-dir=/home/liu/actions-runner/_work/ccv/ccv/lib/nnc -resource-dir /usr/local/lib/clang/19 -I ../ -I /usr/local/cuda/include -D HAVE_CBLAS -D HAVE_LIBPNG -D HAVE_LIBJPEG -D HAVE_FFTW3 -D HAVE_PTHREAD -D HAVE_LIBLINEAR -D HAVE_TESSERACT -D HAVE_AVCODEC -D HAVE_AVFORMAT -D HAVE_AVUTIL -D HAVE_SWSCALE -D HAVE_SSE2 -D HAVE_GSL -D HAVE_CUDA -D HAVE_CUDNN -D HAVE_NCCL -D USE_SYSTEM_CUB -I /usr/local/include -internal-isystem /usr/local/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/12/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O3 -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/liu/actions-runner/_work/ccv/ccv/_analyze/2026-07-31-161031-389540-1 -x c ccv_cnnp_model.c
1#include "ccv_nnc.h"
2#include "ccv_nnc_easy.h"
3#include "ccv_nnc_internal.h"
4#include "ccv_internal.h"
5#include "_ccv_cnnp_model.h"
6#include "_ccv_nnc_graph.h"
7#include "_ccv_nnc_symbolic_graph.h"
8#ifdef HAVE_CUDA1
9#include "gpu/ccv_nnc_compat.h"
10#endif
11
12// MARK - Level-5 API
13
14ccv_cnnp_model_io_t ccv_cnnp_model_apply(ccv_cnnp_model_t* const model, const ccv_cnnp_model_io_t* const inputs, const int input_size)
15{
16 if (!model->io)
17 model->io = ccv_array_new(sizeof(ccv_cnnp_model_io_t), 1, 0);
18 ccv_cnnp_model_io_t model_io = ccmallocmalloc(sizeof(struct ccv_cnnp_model_io_s) + sizeof(ccv_nnc_tensor_symbol_t) * model->output_size);
19 model_io->param_ref = 0;
20 model_io->param_sel = 0;
21 model_io->visit = 0;
22 model_io->model = model;
23 model_io->dependencies = 0;
24 model_io->dependents = 0;
25 model_io->outgoings = 0;
26 model_io->outputs = (ccv_nnc_tensor_symbol_t*)(model_io + 1);
27 ccv_array_push(model->io, &model_io);
28 if (input_size > 0)
29 {
30 model_io->incomings = ccv_array_new(sizeof(ccv_cnnp_model_io_t), input_size, 0);
31 ccv_array_resize(model_io->incomings, input_size);
32 int i;
33 memcpy(ccv_array_get(model_io->incomings, 0)((void*)(((char*)((model_io->incomings)->data)) + (size_t
)(model_io->incomings)->rsize * (size_t)(0)))
, inputs, sizeof(ccv_cnnp_model_io_t) * input_size);
34 for (i = 0; i < input_size; i++)
35 {
36 if (!inputs[i]->outgoings)
37 inputs[i]->outgoings = ccv_array_new(sizeof(ccv_cnnp_model_io_t), 1, 0);
38 ccv_array_push(inputs[i]->outgoings, &model_io);
39 }
40 } else {
41 model_io->incomings = 0;
42 }
43 return model_io;
44}
45
46void ccv_cnnp_model_add_dependencies(ccv_cnnp_model_io_t model_io, const ccv_cnnp_model_io_t* const dependencies, const int dependency_size)
47{
48 assert(dependency_size > 0)((void) sizeof ((dependency_size > 0) ? 1 : 0), __extension__
({ if (dependency_size > 0) ; else __assert_fail ("dependency_size > 0"
, "ccv_cnnp_model.c", 48, __extension__ __PRETTY_FUNCTION__);
}))
;
49 if (!model_io->dependencies)
50 model_io->dependencies = ccv_array_new(sizeof(ccv_cnnp_model_io_t), dependency_size, 0);
51 int i, j;
52 for (i = 0; i < dependency_size; i++)
53 {
54 int flag = 0;
55 // Check if it is already exist or not.
56 for (j = 0; !flag && j < model_io->dependencies->rnum; j++)
57 if (*(ccv_cnnp_model_io_t*)ccv_array_get(model_io->dependencies, j)((void*)(((char*)((model_io->dependencies)->data)) + (size_t
)(model_io->dependencies)->rsize * (size_t)(j)))
== dependencies[i])
58 flag = 1;
59 if (flag)
60 continue;
61 ccv_array_push(model_io->dependencies, dependencies + i);
62 ++dependencies[i]->dependents;
63 }
64}
65
66int ccv_cnnp_model_output_size(const ccv_cnnp_model_t* const model)
67{
68 return model->output_size;
69}
70
71int ccv_cnnp_model_is_trainable(const ccv_cnnp_model_t* const model)
72{
73 // If the model is compiled, it is default to 1 unless it is not.
74 if (model->compiled_data)
75 return model->is_trainable >= 0 ? model->is_trainable : 1;
76 return model->is_trainable;
77}
78
79ccv_cnnp_model_io_t ccv_cnnp_model_parameters(ccv_cnnp_model_t* const model, const int selector, const int index)
80{
81 if (!model->io)
82 model->io = ccv_array_new(sizeof(ccv_cnnp_model_io_t), 1, 0);
83 ccv_cnnp_model_io_t model_io = ccmallocmalloc(sizeof(struct ccv_cnnp_model_io_s));
84 model_io->param_ref = index >= 0 ? index + 1 : ALL_PARAMETERS-1;
85 model_io->param_sel = selector >= 0 ? selector + 1 : ALL_PARAMETERS-1;
86 model_io->visit = 0;
87 model_io->model = model;
88 model_io->outputs = 0;
89 model_io->dependencies = 0;
90 model_io->dependents = 0;
91 model_io->incomings = 0;
92 model_io->outgoings = 0;
93 ccv_array_push(model->io, &model_io);
94 return model_io;
95}
96
97void ccv_cnnp_model_notify_hook(ccv_cnnp_model_t* const model, ccv_cnnp_model_notify_f func, void* const context)
98{
99 model->notify_hook.func = func;
100 model->notify_hook.context = context;
101}
102
103void ccv_cnnp_model_notify(const ccv_cnnp_model_t* const model, const int tag, void* const payload)
104{
105 if (model->notify_hook.func)
106 model->notify_hook.func(model, tag, payload, model->notify_hook.context);
107 if (model->isa->notify)
108 model->isa->notify(model, tag, payload);
109}
110
111static int _ccv_nnc_array_dedup_graph_exec_symbols(ccv_nnc_graph_exec_symbol_t* const graph_exec_symbols, int graph_exec_symbol_size)
112{
113 int i, j;
114 for (i = 0; i < graph_exec_symbol_size; i++)
115 {
116 ccv_nnc_graph_exec_symbol_t* const graph_exec_symbol = graph_exec_symbols + i;
117 // Check whether this tensor symbol has any duplicate.
118 for (j = i + 1; j < graph_exec_symbol_size;)
119 {
120 ccv_nnc_graph_exec_symbol_t* const other_symbol = graph_exec_symbols + j;
121 // If there is a same tensor symbol, remove it.
122 if (other_symbol->d == graph_exec_symbol->d && other_symbol->graph == graph_exec_symbol->graph)
123 {
124 if (j + 1 < graph_exec_symbol_size)
125 *other_symbol = graph_exec_symbols[graph_exec_symbol_size - 1];
126 --graph_exec_symbol_size;
127 continue;
128 }
129 ++j;
130 }
131 }
132 return graph_exec_symbol_size;
133}
134
135void ccv_cnnp_model_add_to_array(void* const context, const ccv_nnc_tensor_symbol_t symbol, const int is_trainable)
136{
137 ccv_cnnp_model_add_to_array_context_t* const add_to_array_context = (ccv_cnnp_model_add_to_array_context_t*)context;
138 ccv_cnnp_model_t* const model = add_to_array_context->sequence->model;
139 int i;
140 if (add_to_array_context->add_parameter_indices && !model->parameter_indices)
141 model->parameter_indices = ccv_array_new(sizeof(int), 0, 0);
142 for (i = 0; i < add_to_array_context->symbols->rnum; i++)
143 {
144 const ccv_nnc_tensor_symbol_t other_symbol = *(ccv_nnc_tensor_symbol_t*)ccv_array_get(add_to_array_context->symbols, i)((void*)(((char*)((add_to_array_context->symbols)->data
)) + (size_t)(add_to_array_context->symbols)->rsize * (
size_t)(i)))
;
145 if (other_symbol.d == symbol.d && other_symbol.graph == symbol.graph)
146 {
147 // Only add to parameter_indices if it is trainable.
148 if (add_to_array_context->add_parameter_indices)
149 ccv_array_add_unique_int(model->parameter_indices, i);
150 // Found it, return, don't add it.
151 return;
152 }
153 }
154 // Only add to parameter_indices if it is trainable.
155 if (add_to_array_context->add_parameter_indices)
156 ccv_array_push(model->parameter_indices, &add_to_array_context->symbols->rnum);
157 // This is a new one, no need to add_unique_int, it is unique.
158 ccv_array_push(add_to_array_context->symbols, &symbol);
159 if (add_to_array_context->trainables)
160 ccv_array_push(add_to_array_context->trainables, &is_trainable);
161 char id[2048];
162 id[0] = add_to_array_context->prefix;
163 id[1] = '-';
164 int total_len = 2;
165 for (i = 0; i < add_to_array_context->sequence->sequences->rnum; i++)
166 {
167 const ccv_cnnp_model_name_t* const name = (ccv_cnnp_model_name_t*)ccv_array_get(add_to_array_context->sequence->sequences, i)((void*)(((char*)((add_to_array_context->sequence->sequences
)->data)) + (size_t)(add_to_array_context->sequence->
sequences)->rsize * (size_t)(i)))
;
168 int len;
169 if (name->name && name->name[0] != '\0')
170 len = snprintf(id + total_len, 2048 - total_len, "%s-%d-", name->name, name->sequence);
171 else
172 len = snprintf(id + total_len, 2048 - total_len, "%d-", name->sequence);
173 total_len += len;
174 if (total_len >= 2047)
175 break;
176 }
177 if (total_len < 2047)
178 total_len += snprintf(id + total_len, 2048 - total_len, "%d", add_to_array_context->sequence->it);
179 assert(total_len < 2048)((void) sizeof ((total_len < 2048) ? 1 : 0), __extension__
({ if (total_len < 2048) ; else __assert_fail ("total_len < 2048"
, "ccv_cnnp_model.c", 179, __extension__ __PRETTY_FUNCTION__)
; }))
;
180 char *heap_id = (char*)ccmallocmalloc(total_len + 1);
181 memcpy(heap_id, id, total_len + 1);
182 ccv_array_push(add_to_array_context->ids, &heap_id);
183 ++add_to_array_context->sequence->it;
184}
185
186static void _ccv_cnnp_compiled_data_init(ccv_cnnp_compiled_data_t* const compiled_data, const int output_size, ccv_array_t* const gradient_checkpoints)
187{
188 compiled_data->f = compiled_data->fits + output_size;
189 compiled_data->xpu_alloc.mp_hdr = -1;
190 compiled_data->xpu_alloc.freed = kh_init(dy_str)kh_init_dy_str();
191 compiled_data->xpu_alloc.allocd = kh_init(dy_alloc)kh_init_dy_alloc();
192 compiled_data->gradient_checkpoints = gradient_checkpoints;
193}
194
195static int _ccv_cnnp_model_root_parallel_count(const ccv_cnnp_model_t* const model)
196{
197 return ccv_max(model->parallel_count, 1)({ typeof (model->parallel_count) _a = (model->parallel_count
); typeof (1) _b = (1); (_a > _b) ? _a : _b; })
;
198}
199
200static int _ccv_cnnp_model_effective_parallel_count(const ccv_cnnp_model_t* const model)
201{
202 int parallel_count = _ccv_cnnp_model_root_parallel_count(model);
203 if (model->graph && model->graph->data_parallel.count > parallel_count)
204 parallel_count = model->graph->data_parallel.count;
205 return parallel_count;
206}
207
208static int _ccv_cnnp_compiled_data_parallel_count(const ccv_cnnp_model_t* const model, const ccv_cnnp_compiled_data_t* const compiled_data)
209{
210 return compiled_data->parallel_count > 0 ? compiled_data->parallel_count : _ccv_cnnp_model_effective_parallel_count(model);
211}
212
213ccv_nnc_tensor_symbol_t ccv_cnnp_model_get_symbol(ccv_cnnp_model_t* const self, const ccv_nnc_tensor_symbol_t symbol)
214{
215 assert(self->data)((void) sizeof ((self->data) ? 1 : 0), __extension__ ({ if
(self->data) ; else __assert_fail ("self->data", "ccv_cnnp_model.c"
, 215, __extension__ __PRETTY_FUNCTION__); }))
;
216 ccv_cnnp_model_build_data_t* const build_data = (ccv_cnnp_model_build_data_t*)self->data;
217 if (build_data->parallel_count <= 1 || build_data->parallel_rank == 0)
218 return symbol;
219 const int rank = build_data->parallel_rank;
220 assert(rank > 0)((void) sizeof ((rank > 0) ? 1 : 0), __extension__ ({ if (
rank > 0) ; else __assert_fail ("rank > 0", "ccv_cnnp_model.c"
, 220, __extension__ __PRETTY_FUNCTION__); }))
;
221 assert(rank < build_data->parallel_count)((void) sizeof ((rank < build_data->parallel_count) ? 1
: 0), __extension__ ({ if (rank < build_data->parallel_count
) ; else __assert_fail ("rank < build_data->parallel_count"
, "ccv_cnnp_model.c", 221, __extension__ __PRETTY_FUNCTION__)
; }))
;
222 ccv_nnc_symbolic_graph_t* const graph = (ccv_nnc_symbolic_graph_t*)symbol.graph;
223 ccv_nnc_tensor_symbol_t copy = ccv_nnc_tensor_symbol_copy(graph, symbol, rank);
224 if (copy.d != CCV_NNC_NO_TENSOR_SYMBOL)
225 return copy;
226 ccv_nnc_tensor_param_t params = ccv_nnc_tensor_symbol_params(graph, symbol);
227 if (CCV_TENSOR_GET_MEMORY(params.type)((params.type) & 0x3) == CCV_TENSOR_GPU_MEMORY)
228 CCV_TENSOR_SET_DEVICE_ID(params.type, rank)(params.type) = (((params.type) & ~0xfff00) | (((rank) &
0xfff) << 8))
;
229 copy = ccv_nnc_tensor_symbol_new(graph, params, 0);
230 ccv_nnc_tensor_symbol_set_copy(graph, symbol, rank, copy);
231 return copy;
232}
233
234typedef struct {
235 void* old_graph_exec_symbol_new_hook_context;
236 ccv_nnc_graph_exec_symbol_new_hook_f old_graph_exec_symbol_new_hook;
237 ccv_nnc_symbolic_graph_t* graph;
238 ccv_cnnp_model_build_data_t* build_data;
239} ccv_cnnp_model_set_exec_flags_context_t;
240
241static void _ccv_cnnp_model_set_exec_flags(void* context, const ccv_nnc_graph_exec_symbol_t symbol, const ccv_nnc_cmd_t cmd, const ccv_nnc_tensor_symbol_t* const inputs, const int input_size, const ccv_nnc_tensor_symbol_t* const outputs, const int output_size, const char* const name)
242{
243 ccv_cnnp_model_set_exec_flags_context_t* flags_context = (ccv_cnnp_model_set_exec_flags_context_t*)context;
244 if (flags_context->build_data->exec_flags)
245 ccv_nnc_graph_exec_symbol_set_flags(flags_context->graph, symbol, flags_context->build_data->exec_flags);
246 if (flags_context->old_graph_exec_symbol_new_hook)
247 flags_context->old_graph_exec_symbol_new_hook(flags_context->old_graph_exec_symbol_new_hook_context, symbol, cmd, inputs, input_size, outputs, output_size, name);
248}
249
250static void _ccv_cnnp_model_compile(ccv_cnnp_model_t* const model, const ccv_nnc_tensor_param_t* const inputs, const int input_size, const ccv_nnc_cmd_t loss)
251{
252 assert(model->graph)((void) sizeof ((model->graph) ? 1 : 0), __extension__ ({ if
(model->graph) ; else __assert_fail ("model->graph", "ccv_cnnp_model.c"
, 252, __extension__ __PRETTY_FUNCTION__); }))
;
253 model->inputs = ccmallocmalloc(sizeof(ccv_nnc_tensor_symbol_t) * input_size);
254 int i;
255 for (i = 0; i < input_size; i++)
256 model->inputs[i] = ccv_nnc_tensor_symbol_new(model->graph, inputs[i], 0);
257 ccv_array_t* const parameters = ccv_array_new(sizeof(ccv_nnc_tensor_symbol_t), 0, 0);
258 ccv_array_t* const parameter_ids = ccv_array_new(sizeof(char*), 0, 0);
259 ccv_array_t* const parameter_trainables = ccv_array_new(sizeof(int), 0, 0);
260 ccv_cnnp_model_sequence_t model_sequence = {
261 .bank = kh_init(ccv_cnnp_model_name_bank)kh_init_ccv_cnnp_model_name_bank()
262 };
263 ccv_cnnp_model_add_to_array_context_t add_to_parameter_context = {
264 .add_parameter_indices = 1,
265 .prefix = 't',
266 .sequence = &model_sequence,
267 .symbols = parameters,
268 .ids = parameter_ids,
269 .trainables = parameter_trainables,
270 };
271 ccv_array_t* const internals = ccv_array_new(sizeof(ccv_nnc_tensor_symbol_t), 0, 0);
272 ccv_array_t* const internal_ids = ccv_array_new(sizeof(char*), 0, 0);
273 ccv_cnnp_model_add_to_array_context_t add_to_output_context = {
274 .add_parameter_indices = 0,
275 .prefix = 'r',
276 .sequence = &model_sequence,
277 .symbols = internals,
278 .ids = internal_ids,
279 .trainables = 0,
280 };
281 ccv_cnnp_model_build_data_t build_data = {
282 .exec_flags = 0,
283 .is_trainable = model->is_trainable >= 0 ? model->is_trainable : 1,
284 .parallel_count = 1,
285 .parallel_rank = 0,
286 .model_sequence = &model_sequence,
287 .add_to_array = ccv_cnnp_model_add_to_array,
288 .parameters = parameters,
289 .context = {
290 .add_to_parameter = &add_to_parameter_context,
291 .add_to_output = &add_to_output_context,
292 },
293 .gradient_checkpoints = 0,
294 };
295 model->data = &build_data;
296 ccv_cnnp_model_set_exec_flags_context_t flags_context = {
297 .graph = model->graph,
298 .build_data = &build_data,
299 .old_graph_exec_symbol_new_hook = 0,
300 .old_graph_exec_symbol_new_hook_context = 0
301 };
302 flags_context.old_graph_exec_symbol_new_hook_context = ccv_nnc_graph_exec_symbol_new_hook(model->graph, _ccv_cnnp_model_set_exec_flags, &flags_context, &flags_context.old_graph_exec_symbol_new_hook);
303 ccv_cnnp_model_build(model, model->graph, model->inputs, input_size, 0, 0);
304 // Reset back to previous hook.
305 ccv_nnc_graph_exec_symbol_new_hook(model->graph, flags_context.old_graph_exec_symbol_new_hook, flags_context.old_graph_exec_symbol_new_hook_context, 0);
306 for (i = 0; i < model->output_size; i++)
307 {
308 const ccv_nnc_tensor_symbol_t output = model->outputs[i];
309 const ccv_nnc_tensor_symbol_t alias_to = ccv_nnc_tensor_symbol_alias_to(model->graph, output);
310 if (alias_to.d == CCV_NNC_NO_TENSOR_SYMBOL)
311 continue;
312 // If output is an alias, insert data transform regardless for result correctness (we cannot bind an alias). You can check ccv_nnc_tensor_bind_symbol method
313 // to see that we can correctly bind a tensor which from it, has aliases, but we cannot bind an alias tensor correctly (this is expected, sort of, to be
314 // honest, because we cannot handle cases of alias is part of the original tensor but bind differently).
315 const ccv_nnc_tensor_param_t output_params = ccv_nnc_tensor_symbol_params(model->graph, output);
316 model->outputs[i] = ccv_nnc_tensor_symbol_new(model->graph, output_params, 0);
317 ccv_nnc_graph_exec_symbol_t make_contiguous = ccv_nnc_graph_exec_symbol_new(model->graph, CMD_FORMAT_TRANSFORM_FORWARD()ccv_nnc_cmd(CCV_NNC_FORMAT_TRANSFORM_FORWARD, 0, ccv_nnc_cmd_auto
, 0)
, &output, 1, model->outputs + i, 1, "contiguous");
318 ccv_nnc_graph_exec_symbol_set_flags(model->graph, make_contiguous, CCV_NNC_GRAPH_EXEC_DISABLE_OPT);
319 }
320 model->data = 0;
321 kh_destroy(ccv_cnnp_model_name_bank, model_sequence.bank)kh_destroy_ccv_cnnp_model_name_bank(model_sequence.bank);
322 if (model_sequence.sequences)
323 ccv_array_free(model_sequence.sequences);
324 // Check if there are parameters that are not trainables. If there are, we will allocate uint64 bitmap to record that.
325 int not_trainables = 0;
326 // Assert no parameter is alias.
327 for (i = 0; i < parameters->rnum; i++)
328 {
329 const ccv_nnc_tensor_symbol_t parameter = *(ccv_nnc_tensor_symbol_t*)ccv_array_get(parameters, i)((void*)(((char*)((parameters)->data)) + (size_t)(parameters
)->rsize * (size_t)(i)))
;
330 const ccv_nnc_tensor_symbol_t alias_to = ccv_nnc_tensor_symbol_alias_to(parameter.graph, parameter);
331 assert(alias_to.graph == 0)((void) sizeof ((alias_to.graph == 0) ? 1 : 0), __extension__
({ if (alias_to.graph == 0) ; else __assert_fail ("alias_to.graph == 0"
, "ccv_cnnp_model.c", 331, __extension__ __PRETTY_FUNCTION__)
; }))
; // Cannot find the one alias to.
332 if (*(int*)ccv_array_get(parameter_trainables, i)((void*)(((char*)((parameter_trainables)->data)) + (size_t
)(parameter_trainables)->rsize * (size_t)(i)))
== 0)
333 not_trainables = 1;
334 }
335 assert(parameters->rnum == parameter_trainables->rnum)((void) sizeof ((parameters->rnum == parameter_trainables->
rnum) ? 1 : 0), __extension__ ({ if (parameters->rnum == parameter_trainables
->rnum) ; else __assert_fail ("parameters->rnum == parameter_trainables->rnum"
, "ccv_cnnp_model.c", 335, __extension__ __PRETTY_FUNCTION__)
; }))
;
336 uint64_t* parameter_flags = 0;
337 if (not_trainables)
338 {
339 parameter_flags = (uint64_t*)cccalloccalloc(((parameters->rnum + 63) >> 6), sizeof(uint64_t));
340 for (i = 0; i < parameter_trainables->rnum; i++)
341 if (*(int*)ccv_array_get(parameter_trainables, i)((void*)(((char*)((parameter_trainables)->data)) + (size_t
)(parameter_trainables)->rsize * (size_t)(i)))
)
342 parameter_flags[i >> 6] |= ((uint64_t)1 << (i & 63));
343 }
344 ccv_array_free(parameter_trainables);
345 // Assert no internal is alias.
346 for (i = 0; i < internals->rnum; i++)
347 {
348 const ccv_nnc_tensor_symbol_t internal = *(ccv_nnc_tensor_symbol_t*)ccv_array_get(internals, i)((void*)(((char*)((internals)->data)) + (size_t)(internals
)->rsize * (size_t)(i)))
;
349 const ccv_nnc_tensor_symbol_t alias_to = ccv_nnc_tensor_symbol_alias_to(internal.graph, internal);
350 assert(alias_to.graph == 0)((void) sizeof ((alias_to.graph == 0) ? 1 : 0), __extension__
({ if (alias_to.graph == 0) ; else __assert_fail ("alias_to.graph == 0"
, "ccv_cnnp_model.c", 350, __extension__ __PRETTY_FUNCTION__)
; }))
; // Cannot find the one alias to.
351 }
352 const int output_size = model->output_size;
353 ccv_nnc_graph_exec_symbol_autogen(model->graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
354 const int parameters_rnum = parameters->rnum;
355 if (input_size > 0)
356 {
357 ccv_array_resize(parameters, parameters_rnum + input_size);
358 memcpy(ccv_array_get(parameters, parameters_rnum)((void*)(((char*)((parameters)->data)) + (size_t)(parameters
)->rsize * (size_t)(parameters_rnum)))
, model->inputs, input_size * sizeof(ccv_nnc_tensor_symbol_t));
359 }
360 ccv_nnc_symbolic_graph_simplify(model->graph,
361 SYMBOLIC_GRAPH_PASSES(CCV_NNC_SIMPLIFY_COMMON_SUBEXPRESSION_ELIMINATION,(const int []){CCV_NNC_SIMPLIFY_COMMON_SUBEXPRESSION_ELIMINATION
, CCV_NNC_SIMPLIFY_DATA_TRANSFER_OPT, CCV_NNC_SIMPLIFY_OPS_FUSION
, CCV_NNC_SIMPLIFY_GRAPH_PRUNING}, (1 +1 +1 +1 +1 +0 +0 +0 +0
+0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +
0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0
+0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 -1)
362 CCV_NNC_SIMPLIFY_DATA_TRANSFER_OPT,(const int []){CCV_NNC_SIMPLIFY_COMMON_SUBEXPRESSION_ELIMINATION
, CCV_NNC_SIMPLIFY_DATA_TRANSFER_OPT, CCV_NNC_SIMPLIFY_OPS_FUSION
, CCV_NNC_SIMPLIFY_GRAPH_PRUNING}, (1 +1 +1 +1 +1 +0 +0 +0 +0
+0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +
0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0
+0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 -1)
363 CCV_NNC_SIMPLIFY_OPS_FUSION,(const int []){CCV_NNC_SIMPLIFY_COMMON_SUBEXPRESSION_ELIMINATION
, CCV_NNC_SIMPLIFY_DATA_TRANSFER_OPT, CCV_NNC_SIMPLIFY_OPS_FUSION
, CCV_NNC_SIMPLIFY_GRAPH_PRUNING}, (1 +1 +1 +1 +1 +0 +0 +0 +0
+0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +
0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0
+0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 -1)
364 CCV_NNC_SIMPLIFY_GRAPH_PRUNING)(const int []){CCV_NNC_SIMPLIFY_COMMON_SUBEXPRESSION_ELIMINATION
, CCV_NNC_SIMPLIFY_DATA_TRANSFER_OPT, CCV_NNC_SIMPLIFY_OPS_FUSION
, CCV_NNC_SIMPLIFY_GRAPH_PRUNING}, (1 +1 +1 +1 +1 +0 +0 +0 +0
+0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +
0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0
+0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 -1)
,
365 ccv_array_get(parameters, 0)((void*)(((char*)((parameters)->data)) + (size_t)(parameters
)->rsize * (size_t)(0)))
, parameters_rnum + input_size,
366 model->outputs, output_size,
367 SYMBOLIC_GRAPH_SOURCES(model->graph)ccv_nnc_symbolic_graph_sources(model->graph), ccv_nnc_symbolic_graph_source_size
(model->graph)
, SYMBOLIC_GRAPH_DESTINATIONS(model->graph)ccv_nnc_symbolic_graph_destinations(model->graph), ccv_nnc_symbolic_graph_destination_size
(model->graph)
);
368 ccv_nnc_graph_exec_symbol_autogen(model->graph, 0, 0, CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
369 // Size it down.
370 parameters->rnum = parameters_rnum;
371 ccv_cnnp_compiled_data_t* compiled_data = model->compiled_data = cccalloccalloc(1, sizeof(ccv_cnnp_compiled_data_t) + sizeof(ccv_nnc_tensor_symbol_t) * (output_size * 2 - 1));
372 _ccv_cnnp_compiled_data_init(compiled_data, output_size, build_data.gradient_checkpoints);
373 const int evaluate_to_size = compiled_data->evaluate.to_size = ccv_nnc_symbolic_graph_destination_size(model->graph);
374 assert(evaluate_to_size > 0)((void) sizeof ((evaluate_to_size > 0) ? 1 : 0), __extension__
({ if (evaluate_to_size > 0) ; else __assert_fail ("evaluate_to_size > 0"
, "ccv_cnnp_model.c", 374, __extension__ __PRETTY_FUNCTION__)
; }))
;
375 compiled_data->evaluate.tos = ccmallocmalloc(sizeof(ccv_nnc_graph_exec_symbol_t) * evaluate_to_size);
376 memcpy(compiled_data->evaluate.tos, ccv_nnc_symbolic_graph_destinations(model->graph), sizeof(ccv_nnc_graph_exec_symbol_t) * evaluate_to_size);
377 compiled_data->loss = loss;
378 if (loss.cmd == CCV_NNC_NOOP)
379 {
380 // If no loss function provided, there is no fits.
381 for (i = 0; i < output_size; i++)
382 {
383 compiled_data->fits[i] = NO_TENSOR_SYMBOL(const ccv_nnc_tensor_symbol_t){.d = CCV_NNC_NO_TENSOR_SYMBOL
}
;
384 const ccv_nnc_tensor_symbol_t alias_to = ccv_nnc_tensor_symbol_alias_to(model->graph, model->outputs[i]);
385 if (alias_to.d < 0)
386 compiled_data->f[i] = model->outputs[i];
387 else { // We cannot differentiate against an alias, therefore, we have to verify this output is full, and we can diff against the original.
388 int ofs[CCV_NNC_MAX_DIM_ALLOC(12)];
389 int inc[CCV_NNC_MAX_DIM_ALLOC(12)];
390 ccv_nnc_tensor_symbol_alias_params(model->graph, model->outputs[i], ofs, inc);
391 int j;
392 for (j = 0; j < CCV_NNC_MAX_DIM_ALLOC(12); j++)
393 { assert(ofs[j] == 0)((void) sizeof ((ofs[j] == 0) ? 1 : 0), __extension__ ({ if (
ofs[j] == 0) ; else __assert_fail ("ofs[j] == 0", "ccv_cnnp_model.c"
, 393, __extension__ __PRETTY_FUNCTION__); }))
; } // There is no ofs.
394 compiled_data->f[i] = alias_to; // Unfortunately, I cannot assert the size yet.
395 }
396 }
397 } else {
398 for (i = 0; i < output_size; i++)
399 {
400 const ccv_nnc_tensor_param_t info = ccv_nnc_tensor_symbol_params(model->graph, model->outputs[i]);
401 const ccv_nnc_tensor_symbol_t fit = compiled_data->fits[i] = ccv_nnc_tensor_symbol_new(model->graph, info, 0);
402 compiled_data->f[i] = ccv_nnc_tensor_symbol_new(model->graph, ccv_nnc_tensor_auto, 0);
403 ccv_nnc_graph_exec_symbol_new(model->graph, loss, TENSOR_SYMBOL_LIST(model->outputs[i], fit)(const ccv_nnc_tensor_symbol_t []){model->outputs[i], fit}
, (1 +1 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0
+0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +
0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0
+0 +0 +0 -1)
, TENSOR_SYMBOL_LIST(compiled_data->f[i])(const ccv_nnc_tensor_symbol_t []){compiled_data->f[i]}, (
1 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0
+0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +
0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0
+0 +0 -1)
, 0);
404 }
405 }
406 if (loss.cmd != CCV_NNC_NOOP)
407 {
408 ccv_nnc_graph_exec_symbol_autogen(model->graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
409 ccv_nnc_symbolic_graph_simplify(model->graph,
410 SYMBOLIC_GRAPH_PASSES(CCV_NNC_SIMPLIFY_OPS_FUSION)(const int []){CCV_NNC_SIMPLIFY_OPS_FUSION}, (1 +1 +0 +0 +0 +
0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0
+0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +
0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 -1)
, // Only do Ops fusion, in this way, we can fuse the loss function.
411 0, 0, // No need to provide binds at this point.
412 compiled_data->f, model->output_size,
413 SYMBOLIC_GRAPH_SOURCES(model->graph)ccv_nnc_symbolic_graph_sources(model->graph), ccv_nnc_symbolic_graph_source_size
(model->graph)
, SYMBOLIC_GRAPH_DESTINATIONS(model->graph)ccv_nnc_symbolic_graph_destinations(model->graph), ccv_nnc_symbolic_graph_destination_size
(model->graph)
);
414 ccv_nnc_graph_exec_symbol_autogen(model->graph, 0, 0, CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
415 }
416 // If inputs are from GPU, stream type is GPU.
417 compiled_data->parameters = parameters;
418 compiled_data->parameter_flags = parameter_flags;
419 compiled_data->internals = internals;
420 compiled_data->ids.parameters = parameter_ids;
421 compiled_data->ids.internals = internal_ids;
422 ccv_cnnp_model_gradient_checkpoints_cleanup_after_build(compiled_data, model->graph);
423}
424
425static void _ccv_cnnp_graph_push_graph_exec_symbol(void* context, const ccv_nnc_graph_exec_symbol_t symbol, const ccv_nnc_cmd_t cmd, const ccv_nnc_tensor_symbol_t* const inputs, const int input_size, const ccv_nnc_tensor_symbol_t* const outputs, const int output_size, const char* const name)
426{
427 ccv_array_t* const stack = (ccv_array_t*)context;
428 ccv_array_push(stack, &symbol.d);
429}
430
431static void _ccv_nnc_tensor_symbol_reinit(const ccv_nnc_symbolic_graph_t* const src_graph, ccv_nnc_symbolic_graph_t* const dest_graph, const int src_index, const int dest_index)
432{
433 int src_alias_ref = src_index;
434 const ccv_nnc_tensor_symbol_info_t* src_info = (ccv_nnc_tensor_symbol_info_t*)ccv_array_get(src_graph->tensor_symbol_info, src_alias_ref)((void*)(((char*)((src_graph->tensor_symbol_info)->data
)) + (size_t)(src_graph->tensor_symbol_info)->rsize * (
size_t)(src_alias_ref)))
;
435 while (src_info->alias_ref)
436 {
437 src_alias_ref = src_info->alias_ref - 1;
438 src_info = (ccv_nnc_tensor_symbol_info_t*)ccv_array_get(src_graph->tensor_symbol_info, src_alias_ref)((void*)(((char*)((src_graph->tensor_symbol_info)->data
)) + (size_t)(src_graph->tensor_symbol_info)->rsize * (
size_t)(src_alias_ref)))
;
439 }
440 int dest_alias_ref = dest_index;
441 const ccv_nnc_tensor_symbol_info_t* dest_info = (ccv_nnc_tensor_symbol_info_t*)ccv_array_get(dest_graph->tensor_symbol_info, dest_alias_ref)((void*)(((char*)((dest_graph->tensor_symbol_info)->data
)) + (size_t)(dest_graph->tensor_symbol_info)->rsize * (
size_t)(dest_alias_ref)))
;
442 while (dest_info->alias_ref)
443 {
444 dest_alias_ref = dest_info->alias_ref - 1;
445 dest_info = (ccv_nnc_tensor_symbol_info_t*)ccv_array_get(dest_graph->tensor_symbol_info, dest_alias_ref)((void*)(((char*)((dest_graph->tensor_symbol_info)->data
)) + (size_t)(dest_graph->tensor_symbol_info)->rsize * (
size_t)(dest_alias_ref)))
;
446 }
447 assert((src_alias_ref != src_index) == (dest_alias_ref != dest_index))((void) sizeof (((src_alias_ref != src_index) == (dest_alias_ref
!= dest_index)) ? 1 : 0), __extension__ ({ if ((src_alias_ref
!= src_index) == (dest_alias_ref != dest_index)) ; else __assert_fail
("(src_alias_ref != src_index) == (dest_alias_ref != dest_index)"
, "ccv_cnnp_model.c", 447, __extension__ __PRETTY_FUNCTION__)
; }))
;
448 if (src_alias_ref != src_index)
449 {
450 const ccv_nnc_tensor_symbol_t src_alias_symbol = {
451 .d = src_alias_ref,
452 .graph = src_graph
453 };
454 const ccv_nnc_tensor_symbol_t dest_alias_symbol = {
455 .d = dest_alias_ref,
456 .graph = dest_graph
457 };
458 const ccv_nnc_tensor_param_t params = ccv_nnc_tensor_symbol_params(src_graph, src_alias_symbol);
459 ccv_nnc_tensor_symbol_set(dest_graph, dest_alias_symbol, params);
460 }
461 const ccv_nnc_tensor_symbol_t src_symbol = {
462 .d = src_index,
463 .graph = src_graph
464 };
465 const ccv_nnc_tensor_symbol_t dest_symbol = {
466 .d = dest_index,
467 .graph = dest_graph
468 };
469 const ccv_nnc_tensor_param_t params = ccv_nnc_tensor_symbol_params(src_graph, src_symbol);
470 ccv_nnc_tensor_symbol_set(dest_graph, dest_symbol, params);
471 int ofs[CCV_NNC_MAX_DIM_ALLOC(12)];
472 int inc[CCV_NNC_MAX_DIM_ALLOC(12)];
473 if (0 == ccv_nnc_tensor_symbol_alias_params(src_graph, src_symbol, ofs, inc))
474 ccv_nnc_tensor_symbol_alias_set(dest_graph, dest_symbol, ofs, inc);
475}
476
477static int _ccv_nnc_tensor_symbol_check_dim(const ccv_nnc_symbolic_graph_t* const src_graph, ccv_nnc_symbolic_graph_t* const dest_graph, const int src_index, const int dest_index)
478{
479 const ccv_nnc_tensor_symbol_t src_symbol = {
480 .d = src_index,
481 .graph = src_graph
482 };
483 const ccv_nnc_tensor_param_t src_params = ccv_nnc_tensor_symbol_params(src_graph, src_symbol);
484 const ccv_nnc_tensor_symbol_t dest_symbol = {
485 .d = dest_index,
486 .graph = dest_graph
487 };
488 const ccv_nnc_tensor_param_t dest_params = ccv_nnc_tensor_symbol_params(dest_graph, dest_symbol);
489 if (src_params.dim[0] == 0 || dest_params.dim[0] == 0)
490 return 1;
491 return memcmp(src_params.dim, dest_params.dim, sizeof(src_params.dim)) == 0;
492}
493
494static void _ccv_cnnp_model_gradient_init(ccv_cnnp_model_t* const model, const int gradient_mode, const uint64_t disable_outgrad, ccv_nnc_tensor_t* const* const fits, const int fit_size);
495static void _ccv_cnnp_compiled_data_graph_free(ccv_cnnp_compiled_data_t* const compiled_data);
496
497typedef struct {
498 int parallel_count;
499 ccv_nnc_symbolic_graph_t* graph;
500 ccv_nnc_graph_exec_arena_t* graph_exec_arena;
501} ccv_nnc_graph_exec_update_t;
502
503static void _ccv_cnnp_cmd_update_for_execs(void* const context, const ccv_nnc_graph_exec_symbol_t symbol, const ccv_nnc_cmd_t cmd, const ccv_nnc_hint_t hint)
504{
505 ccv_nnc_graph_exec_update_t* const graph_exec_update = (ccv_nnc_graph_exec_update_t*)context;
506 ccv_nnc_graph_exec_arena_t* const graph_exec_arena = graph_exec_update->graph_exec_arena;
507 ccv_nnc_graph_exec_t graph_exec = ccv_nnc_graph_exec_from_symbol(graph_exec_arena, symbol);
508 ccv_nnc_graph_exec_set(graph_exec.graph, graph_exec, cmd);
509 ccv_nnc_graph_exec_set_hint(graph_exec.graph, graph_exec, hint);
510 const ccv_nnc_symbolic_graph_t* const graph = graph_exec_update->graph;
511 const int parallel_count = graph_exec_update->parallel_count;
512 int i;
513 for (i = 1; i < parallel_count; i++)
514 {
515 const ccv_nnc_graph_exec_t copy = ccv_nnc_graph_exec_from_symbol(graph_exec_arena, ccv_nnc_graph_exec_symbol_copy(graph, symbol, i));
516 if (!CCV_NO_GRAPH_EXEC(copy)((copy).graph == 0))
517 {
518 ccv_nnc_graph_exec_set(copy.graph, copy, cmd);
519 ccv_nnc_graph_exec_set_hint(copy.graph, copy, hint);
520 }
521 }
522}
523
524void ccv_cnnp_model_absorb(ccv_cnnp_model_t* const model, ccv_cnnp_model_t* const init, const ccv_nnc_tensor_param_t* const inputs, const int input_size)
525{
526 assert(model->graph)((void) sizeof ((model->graph) ? 1 : 0), __extension__ ({ if
(model->graph) ; else __assert_fail ("model->graph", "ccv_cnnp_model.c"
, 526, __extension__ __PRETTY_FUNCTION__); }))
;
527 assert(model->compiled_data)((void) sizeof ((model->compiled_data) ? 1 : 0), __extension__
({ if (model->compiled_data) ; else __assert_fail ("model->compiled_data"
, "ccv_cnnp_model.c", 527, __extension__ __PRETTY_FUNCTION__)
; }))
;
528 assert(!init->graph)((void) sizeof ((!init->graph) ? 1 : 0), __extension__ ({ if
(!init->graph) ; else __assert_fail ("!init->graph", "ccv_cnnp_model.c"
, 528, __extension__ __PRETTY_FUNCTION__); }))
;
529 ccv_cnnp_compiled_data_t* const compiled_data = model->compiled_data;
530 init->graph = ccv_nnc_symbolic_graph_new();
531 ccv_array_t* const stack = ccv_array_new(sizeof(int), 0, 0);
532 ccv_nnc_graph_exec_symbol_new_hook(init->graph, _ccv_cnnp_graph_push_graph_exec_symbol, stack, 0);
533 _ccv_cnnp_model_compile(init, inputs, input_size, compiled_data->loss);
534 init->parallel_count = model->parallel_count;
535 init->memory_compression = model->memory_compression;
536 init->memory_reduction = model->memory_reduction;
537 init->gradient_checkpointing = model->gradient_checkpointing;
538 init->compiled_data->stream_type = model->compiled_data->stream_type;
539 init->compiled_data->minimize.minimizer = model->compiled_data->minimize.minimizer;
540 init->compiled_data->minimize.max_saved_aux_size = model->compiled_data->minimize.max_saved_aux_size;
541 if (model->compiled_data->gradient_mode != CCV_CNNP_COMPILED_DATA_GRADIENT_NONE)
542 _ccv_cnnp_model_gradient_init(init, model->compiled_data->gradient_mode, model->compiled_data->disable_outgrad, 0, 0);
543 ccv_nnc_graph_exec_symbol_new_hook(init->graph, 0, 0, 0);
544 ccv_nnc_symbolic_graph_tensor_auto(init->graph, TRAVERSE_FULL0,0,0,0);
545 int i, j;
546 // Verify parameters, internals and saved_aux in both graph has the same dimensionality.
547 for (i = 0; i < compiled_data->parameters->rnum; i++)
548 {
549 const int d = ((ccv_nnc_tensor_symbol_t*)ccv_array_get(compiled_data->parameters, i)((void*)(((char*)((compiled_data->parameters)->data)) +
(size_t)(compiled_data->parameters)->rsize * (size_t)(
i)))
)->d;
550 assert(_ccv_nnc_tensor_symbol_check_dim(model->graph, init->graph, d, d))((void) sizeof ((_ccv_nnc_tensor_symbol_check_dim(model->graph
, init->graph, d, d)) ? 1 : 0), __extension__ ({ if (_ccv_nnc_tensor_symbol_check_dim
(model->graph, init->graph, d, d)) ; else __assert_fail
("_ccv_nnc_tensor_symbol_check_dim(model->graph, init->graph, d, d)"
, "ccv_cnnp_model.c", 550, __extension__ __PRETTY_FUNCTION__)
; }))
;
551 }
552 for (i = 0; i < compiled_data->internals->rnum; i++)
553 {
554 const int d = ((ccv_nnc_tensor_symbol_t*)ccv_array_get(compiled_data->internals, i)((void*)(((char*)((compiled_data->internals)->data)) + (
size_t)(compiled_data->internals)->rsize * (size_t)(i))
)
)->d;
555 assert(_ccv_nnc_tensor_symbol_check_dim(model->graph, init->graph, d, d))((void) sizeof ((_ccv_nnc_tensor_symbol_check_dim(model->graph
, init->graph, d, d)) ? 1 : 0), __extension__ ({ if (_ccv_nnc_tensor_symbol_check_dim
(model->graph, init->graph, d, d)) ; else __assert_fail
("_ccv_nnc_tensor_symbol_check_dim(model->graph, init->graph, d, d)"
, "ccv_cnnp_model.c", 555, __extension__ __PRETTY_FUNCTION__)
; }))
;
556 }
557 // Update inputs.
558 assert(model->input_size == init->input_size)((void) sizeof ((model->input_size == init->input_size)
? 1 : 0), __extension__ ({ if (model->input_size == init->
input_size) ; else __assert_fail ("model->input_size == init->input_size"
, "ccv_cnnp_model.c", 558, __extension__ __PRETTY_FUNCTION__)
; }))
;
559 for (i = 0; i < model->input_size; i++)
560 if (model->inputs[i].d >= 0)
561 {
562 assert(init->inputs[i].d >= 0)((void) sizeof ((init->inputs[i].d >= 0) ? 1 : 0), __extension__
({ if (init->inputs[i].d >= 0) ; else __assert_fail ("init->inputs[i].d >= 0"
, "ccv_cnnp_model.c", 562, __extension__ __PRETTY_FUNCTION__)
; }))
;
563 _ccv_nnc_tensor_symbol_reinit(init->graph, model->graph, init->inputs[i].d, model->inputs[i].d);
564 }
565 // Update outputs.
566 assert(model->output_size == init->output_size)((void) sizeof ((model->output_size == init->output_size
) ? 1 : 0), __extension__ ({ if (model->output_size == init
->output_size) ; else __assert_fail ("model->output_size == init->output_size"
, "ccv_cnnp_model.c", 566, __extension__ __PRETTY_FUNCTION__)
; }))
;
567 for (i = 0; i < model->output_size; i++)
568 {
569 if (model->outputs[i].d >= 0)
570 {
571 assert(init->outputs[i].d >= 0)((void) sizeof ((init->outputs[i].d >= 0) ? 1 : 0), __extension__
({ if (init->outputs[i].d >= 0) ; else __assert_fail (
"init->outputs[i].d >= 0", "ccv_cnnp_model.c", 571, __extension__
__PRETTY_FUNCTION__); }))
;
572 _ccv_nnc_tensor_symbol_reinit(init->graph, model->graph, init->outputs[i].d, model->outputs[i].d);
573 }
574 if (model->outputs[i].d != model->compiled_data->f[i].d)
575 {
576 assert(init->outputs[i].d != init->compiled_data->f[i].d)((void) sizeof ((init->outputs[i].d != init->compiled_data
->f[i].d) ? 1 : 0), __extension__ ({ if (init->outputs[
i].d != init->compiled_data->f[i].d) ; else __assert_fail
("init->outputs[i].d != init->compiled_data->f[i].d"
, "ccv_cnnp_model.c", 576, __extension__ __PRETTY_FUNCTION__)
; }))
;
577 if (model->compiled_data->f[i].d >= 0)
578 {
579 assert(init->compiled_data->f[i].d >= 0)((void) sizeof ((init->compiled_data->f[i].d >= 0) ?
1 : 0), __extension__ ({ if (init->compiled_data->f[i]
.d >= 0) ; else __assert_fail ("init->compiled_data->f[i].d >= 0"
, "ccv_cnnp_model.c", 579, __extension__ __PRETTY_FUNCTION__)
; }))
;
580 _ccv_nnc_tensor_symbol_reinit(init->graph, model->graph, init->compiled_data->f[i].d, model->compiled_data->f[i].d);
581 }
582 }
583 }
584 // Go through the graph to set tensor on matching symbols
585 for (i = 0; i < stack->rnum; i++)
586 {
587 const int d = *(int*)ccv_array_get(stack, i)((void*)(((char*)((stack)->data)) + (size_t)(stack)->rsize
* (size_t)(i)))
;
588 // If exceed range, skip.
589 if (d >= ccv_nnc_graph_exec_symbol_count(init->graph) ||
590 d >= ccv_nnc_graph_exec_symbol_count(model->graph))
591 continue;
592 const ccv_nnc_graph_exec_symbol_t src_symbol = {
593 .d = d,
594 .graph = init->graph
595 };
596 const ccv_nnc_graph_exec_symbol_t dest_symbol = {
597 .d = d,
598 .graph = model->graph
599 };
600 const ccv_nnc_cmd_t src_cmd = ccv_nnc_graph_exec_symbol_cmd(init->graph, src_symbol);
601 const ccv_nnc_cmd_t dest_cmd = ccv_nnc_graph_exec_symbol_cmd(model->graph, dest_symbol);
602 // If the name doesn't match, skip.
603 if (dest_cmd.cmd != src_cmd.cmd && src_cmd.cmd != CCV_NNC_NOOP)
604 continue;
605 // Now get all the inputs and outputs, if matches, set them.
606 const int* src_inputs;
607 int src_input_size;
608 const int* src_outputs;
609 int src_output_size;
610 ccv_nnc_graph_exec_symbol_io(init->graph, src_symbol, &src_inputs, &src_input_size, &src_outputs, &src_output_size);
611 const int* dest_inputs;
612 int dest_input_size;
613 const int* dest_outputs;
614 int dest_output_size;
615 ccv_nnc_graph_exec_symbol_io(model->graph, dest_symbol, &dest_inputs, &dest_input_size, &dest_outputs, &dest_output_size);
616 // We may have unmatched input / output size because this is the minimizer and it has
617 // different saved_aux (for example, when we shrunk with CMD_NOOP).
618 if (src_input_size != dest_input_size)
619 continue;
620 if (src_output_size != dest_output_size)
621 continue;
622 ccv_nnc_graph_exec_symbol_set(model->graph, dest_symbol, src_cmd);
623 // There may be mismatches of the source tensor symbols and destination tensor symbols. The reason is because
624 // we may later passed-in the minimizer, therefore, we may allocate tensors for minimizer later in the original
625 // graph whereas in the newly created graph, it is streamlined (the minimizer exists from the beginning). That
626 // will make the order of tensor symbols creation different, therefore, exact which tensor is which wrong as
627 // well. However, set a new minimizer won't change the exec symbol ordering, because we never create new exec
628 // symbols after gradient init step. Changing a new minimizer just updated that exec symbols setting, it is not
629 // a new exec symbol.
630 for (j = 0; j < src_input_size; j++)
631 if (src_inputs[j] >= 0)
632 _ccv_nnc_tensor_symbol_reinit(init->graph, model->graph, src_inputs[j], dest_inputs[j]);
633 for (j = 0; j < src_output_size; j++)
634 if (src_outputs[j] >= 0)
635 _ccv_nnc_tensor_symbol_reinit(init->graph, model->graph, src_outputs[j], dest_outputs[j]);
636 }
637 ccv_array_free(stack);
638 // After this, we get all tensors in the model graph resolved through tensor_auto.
639 ccv_nnc_symbolic_graph_tensor_auto(model->graph, TRAVERSE_FULL0,0,0,0);
640 // Verify symbols we get matches.
641 const int parameter_size = compiled_data->parameters->rnum;
642 for (i = 0; i < parameter_size; i++)
643 { assert(((ccv_nnc_tensor_symbol_t*)ccv_array_get(compiled_data->parameters, i))->d == ((ccv_nnc_tensor_symbol_t*)ccv_array_get(init->compiled_data->parameters, i))->d)((void) sizeof ((((ccv_nnc_tensor_symbol_t*)((void*)(((char*)
((compiled_data->parameters)->data)) + (size_t)(compiled_data
->parameters)->rsize * (size_t)(i))))->d == ((ccv_nnc_tensor_symbol_t
*)((void*)(((char*)((init->compiled_data->parameters)->
data)) + (size_t)(init->compiled_data->parameters)->
rsize * (size_t)(i))))->d) ? 1 : 0), __extension__ ({ if (
((ccv_nnc_tensor_symbol_t*)((void*)(((char*)((compiled_data->
parameters)->data)) + (size_t)(compiled_data->parameters
)->rsize * (size_t)(i))))->d == ((ccv_nnc_tensor_symbol_t
*)((void*)(((char*)((init->compiled_data->parameters)->
data)) + (size_t)(init->compiled_data->parameters)->
rsize * (size_t)(i))))->d) ; else __assert_fail ("((ccv_nnc_tensor_symbol_t*)ccv_array_get(compiled_data->parameters, i))->d == ((ccv_nnc_tensor_symbol_t*)ccv_array_get(init->compiled_data->parameters, i))->d"
, "ccv_cnnp_model.c", 643, __extension__ __PRETTY_FUNCTION__)
; }))
; }
644 const int internal_size = compiled_data->internals->rnum;
645 for (i = 0; i < internal_size; i++)
646 { assert(((ccv_nnc_tensor_symbol_t*)ccv_array_get(compiled_data->internals, i))->d == ((ccv_nnc_tensor_symbol_t*)ccv_array_get(init->compiled_data->internals, i))->d)((void) sizeof ((((ccv_nnc_tensor_symbol_t*)((void*)(((char*)
((compiled_data->internals)->data)) + (size_t)(compiled_data
->internals)->rsize * (size_t)(i))))->d == ((ccv_nnc_tensor_symbol_t
*)((void*)(((char*)((init->compiled_data->internals)->
data)) + (size_t)(init->compiled_data->internals)->rsize
* (size_t)(i))))->d) ? 1 : 0), __extension__ ({ if (((ccv_nnc_tensor_symbol_t
*)((void*)(((char*)((compiled_data->internals)->data)) +
(size_t)(compiled_data->internals)->rsize * (size_t)(i
))))->d == ((ccv_nnc_tensor_symbol_t*)((void*)(((char*)((init
->compiled_data->internals)->data)) + (size_t)(init->
compiled_data->internals)->rsize * (size_t)(i))))->d
) ; else __assert_fail ("((ccv_nnc_tensor_symbol_t*)ccv_array_get(compiled_data->internals, i))->d == ((ccv_nnc_tensor_symbol_t*)ccv_array_get(init->compiled_data->internals, i))->d"
, "ccv_cnnp_model.c", 646, __extension__ __PRETTY_FUNCTION__)
; }))
; }
647 // Go through compiled data.
648 if (compiled_data->tensor_arena)
649 {
650 const int flag = ccv_nnc_tensor_arena_reinit(compiled_data->tensor_arena, model->graph);
651 if (flag == 0 && compiled_data->graph_exec_arena)
652 {
653 ccv_nnc_graph_exec_reinit(compiled_data->graph_exec_arena, compiled_data->graph, model->graph);
654 // Since we will reinit, if we previously set is_test, we need to set it again.
655 if (compiled_data->is_test)
656 {
657 const int parallel_count = ccv_max(model->parallel_count, 1)({ typeof (model->parallel_count) _a = (model->parallel_count
); typeof (1) _b = (1); (_a > _b) ? _a : _b; })
;
658 ccv_nnc_graph_exec_update_t update = {
659 .parallel_count = parallel_count,
660 .graph = model->graph,
661 .graph_exec_arena = compiled_data->graph_exec_arena,
662 };
663 ccv_cnnp_model_set_is_test(model, 1, _ccv_cnnp_cmd_update_for_execs, &update);
664 }
665 } else
666 // Free-up tensor arena & graph exec arena.
667 _ccv_cnnp_compiled_data_graph_free(compiled_data);
668 }
669 // There are other compiled graphs, for accum and apply gradients.
670 // However, the main conclusion is, these absorb operations shouldn't impact parameters.
671 // Thus, it won't impact the shape of gradients (only outgrad). Since for outgrad, we
672 // don't allocate ourselves, it is not a concern. For normal gradients, the shape cannot
673 // be changed otherwise parameters' shape will be meaningless. The same goes to internals.
674 // That is why we don't update these compiled graphs at all this point.
675 // Free the model, we've already "absorbed" it.
676 ccv_cnnp_model_free(init);
677}
678
679void ccv_cnnp_model_compile(ccv_cnnp_model_t* const model, const ccv_nnc_tensor_param_t* const inputs, const int input_size, const ccv_nnc_cmd_t minimizer, const ccv_nnc_cmd_t loss)
680{
681 assert(input_size == model->input_size || model->input_size == 0)((void) sizeof ((input_size == model->input_size || model->
input_size == 0) ? 1 : 0), __extension__ ({ if (input_size ==
model->input_size || model->input_size == 0) ; else __assert_fail
("input_size == model->input_size || model->input_size == 0"
, "ccv_cnnp_model.c", 681, __extension__ __PRETTY_FUNCTION__)
; }))
;
682 if (model->input_size == 0)
683 model->input_size = input_size;
684 if (!model->graph) // The graph is not compiled yet.
685 {
686 model->graph = ccv_nnc_symbolic_graph_new();
687 _ccv_cnnp_model_compile(model, inputs, input_size, loss);
688 assert(model->compiled_data)((void) sizeof ((model->compiled_data) ? 1 : 0), __extension__
({ if (model->compiled_data) ; else __assert_fail ("model->compiled_data"
, "ccv_cnnp_model.c", 688, __extension__ __PRETTY_FUNCTION__)
; }))
;
689 int i, flag = 0;
690 for (i = 0; !flag && i < input_size; i++)
691 flag = (CCV_TENSOR_GET_MEMORY(inputs[i].type)((inputs[i].type) & 0x3) == CCV_TENSOR_GPU_MEMORY);
692 // If inputs are from GPU, stream type is GPU.
693 model->compiled_data->stream_type = flag ? CCV_STREAM_CONTEXT_GPU : CCV_STREAM_CONTEXT_CPU;
694 model->compiled_data->minimize.minimizer = minimizer;
695 model->compiled_data->minimize.max_saved_aux_size = ccv_nnc_minimizer_saved_aux_size(minimizer);
696 } else {
697 // Now, finally fill in this part. If the graph is already compiled, we make a copy of the model.
698 // And then absorb the "new model" to the old one.
699 ccv_cnnp_model_t* const init = ccv_cnnp_model_copy(model, model->is_trainable);
700 ccv_cnnp_model_absorb(model, init, inputs, input_size);
701 // Reset minimizer.
702 ccv_cnnp_model_set_minimizer(model, minimizer, 1, 0, 0);
703 }
704}
705
706ccv_cnnp_model_t* ccv_cnnp_model_copy(const ccv_cnnp_model_t* const model, const int is_trainable)
707{
708 ccv_cnnp_model_t* const new_model = _ccv_cnnp_model_copy(model, 0);
709 new_model->is_trainable = is_trainable;
710 return new_model;
711}
712
713void ccv_cnnp_model_tensor_auto(ccv_cnnp_model_t* const model, ccv_nnc_tensor_param_t* const outputs, const int output_size)
714{
715 assert(model->graph)((void) sizeof ((model->graph) ? 1 : 0), __extension__ ({ if
(model->graph) ; else __assert_fail ("model->graph", "ccv_cnnp_model.c"
, 715, __extension__ __PRETTY_FUNCTION__); }))
;
716 assert(output_size == model->output_size)((void) sizeof ((output_size == model->output_size) ? 1 : 0
), __extension__ ({ if (output_size == model->output_size)
; else __assert_fail ("output_size == model->output_size"
, "ccv_cnnp_model.c", 716, __extension__ __PRETTY_FUNCTION__)
; }))
;
717 ccv_nnc_symbolic_graph_t* const graph = model->graph;
718 ccv_nnc_symbolic_graph_tensor_auto(graph, TRAVERSE_FULL0,0,0,0);
719 int i;
720 for (i = 0; i < output_size; i++)
721 {
722 assert(model->outputs[i].d != CCV_NNC_NO_TENSOR_SYMBOL)((void) sizeof ((model->outputs[i].d != CCV_NNC_NO_TENSOR_SYMBOL
) ? 1 : 0), __extension__ ({ if (model->outputs[i].d != CCV_NNC_NO_TENSOR_SYMBOL
) ; else __assert_fail ("model->outputs[i].d != CCV_NNC_NO_TENSOR_SYMBOL"
, "ccv_cnnp_model.c", 722, __extension__ __PRETTY_FUNCTION__)
; }))
;
723 outputs[i] = ccv_nnc_tensor_symbol_params(graph, model->outputs[i]);
724 }
725}
726
727void ccv_cnnp_model_set_workspace_size(ccv_cnnp_model_t* const model, size_t workspace_size)
728{
729 if (workspace_size == model->workspace_size)
730 return;
731 model->workspace_size = workspace_size;
732 ccv_cnnp_compiled_data_t* const compiled_data = model->compiled_data;
733 if (compiled_data && compiled_data->graph)
734 ccv_nnc_graph_autotune(compiled_data->graph, workspace_size, 0, TRAVERSE_FULL0,0,0,0);
735}
736
737size_t ccv_cnnp_model_workspace_size(ccv_cnnp_model_t* const model)
738{
739 return model->workspace_size;
740}
741
742void ccv_cnnp_model_set_data_parallel(ccv_cnnp_model_t* const model, const int parallel)
743{
744 if (parallel == 0)
745 model->parallel_count = ccv_nnc_device_count(CCV_STREAM_CONTEXT_GPU);
746 else
747 model->parallel_count = parallel;
748 ccv_cnnp_compiled_data_t* const compiled_data = model->compiled_data;
749 if (compiled_data)
750 { assert(!compiled_data->graph)((void) sizeof ((!compiled_data->graph) ? 1 : 0), __extension__
({ if (!compiled_data->graph) ; else __assert_fail ("!compiled_data->graph"
, "ccv_cnnp_model.c", 750, __extension__ __PRETTY_FUNCTION__)
; }))
; }
751}
752
753void ccv_cnnp_model_set_max_concurrency(ccv_cnnp_model_t* const model, const int max_stream_count)
754{
755 model->max_stream_count = max_stream_count;
756 ccv_cnnp_compiled_data_t* const compiled_data = model->compiled_data;
757 if (compiled_data)
758 { assert(!compiled_data->graph)((void) sizeof ((!compiled_data->graph) ? 1 : 0), __extension__
({ if (!compiled_data->graph) ; else __assert_fail ("!compiled_data->graph"
, "ccv_cnnp_model.c", 758, __extension__ __PRETTY_FUNCTION__)
; }))
; }
759}
760
761void ccv_cnnp_model_set_memory_compression(ccv_cnnp_model_t* const model, const int memory_compression)
762{
763 model->memory_compression = memory_compression;
764 ccv_cnnp_compiled_data_t* const compiled_data = model->compiled_data;
765 if (compiled_data)
766 { assert(!compiled_data->graph)((void) sizeof ((!compiled_data->graph) ? 1 : 0), __extension__
({ if (!compiled_data->graph) ; else __assert_fail ("!compiled_data->graph"
, "ccv_cnnp_model.c", 766, __extension__ __PRETTY_FUNCTION__)
; }))
; }
767}
768
769void ccv_cnnp_model_set_memory_reduction(ccv_cnnp_model_t* const model, const int memory_reduction)
770{
771 model->memory_reduction = memory_reduction;
772 ccv_cnnp_compiled_data_t* const compiled_data = model->compiled_data;
773 if (compiled_data)
774 { assert(!compiled_data->graph)((void) sizeof ((!compiled_data->graph) ? 1 : 0), __extension__
({ if (!compiled_data->graph) ; else __assert_fail ("!compiled_data->graph"
, "ccv_cnnp_model.c", 774, __extension__ __PRETTY_FUNCTION__)
; }))
; }
775}
776
777void ccv_cnnp_model_set_gradient_checkpointing(ccv_cnnp_model_t* const model, const int gradient_checkpointing)
778{
779 model->gradient_checkpointing = gradient_checkpointing;
780}
781
782int ccv_cnnp_model_gradient_checkpointing(ccv_cnnp_model_t* const model)
783{
784 return model->gradient_checkpointing;
785}
786
787typedef struct {
788 int parallel_count;
789 ccv_nnc_symbolic_graph_t* graph;
790 ccv_cnnp_compiled_data_t* compiled_data;
791 ccv_nnc_tensor_arena_t* tensor_arena;
792} ccv_nnc_tensor_init_states_t;
793
794static int _ccv_cnnp_any_to_init(const ccv_cnnp_compiled_data_t* const compiled_data)
795{
796 int i;
797 const uint32_t* const init_v = CCV_NNC_INIT_V(compiled_data->tensors_init.v)((uint32_t*)((uintptr_t)(compiled_data->tensors_init.v) &
~(uintptr_t)1))
;
798 for (i = 0; i < compiled_data->parameters->rnum; i++)
799 {
800 const int d = ((ccv_nnc_tensor_symbol_t*)ccv_array_get(compiled_data->parameters, i)((void*)(((char*)((compiled_data->parameters)->data)) +
(size_t)(compiled_data->parameters)->rsize * (size_t)(
i)))
)->d;
801 if (!(init_v[d >> 5] & (1u << (d & 0x1f))))
802 return 1;
803 }
804 for (i = 0; i < compiled_data->internals->rnum; i++)
805 {
806 const int d = ((ccv_nnc_tensor_symbol_t*)ccv_array_get(compiled_data->internals, i)((void*)(((char*)((compiled_data->internals)->data)) + (
size_t)(compiled_data->internals)->rsize * (size_t)(i))
)
)->d;
807 if (!(init_v[d >> 5] & (1u << (d & 0x1f))))
808 return 1;
809 }
810 return 0;
811}
812
813static void _ccv_cnnp_init_states_for_tensors(void* const context, const ccv_nnc_cmd_t cmd, const ccv_nnc_hint_t hint, const int flags, ccv_nnc_tensor_t* const input, const ccv_nnc_tensor_symbol_t output_symbol)
814{
815 ccv_nnc_tensor_init_states_t* const tensor_init_states = (ccv_nnc_tensor_init_states_t*)context;
816 ccv_nnc_tensor_arena_t* const tensor_arena = tensor_init_states->tensor_arena;
817 ccv_nnc_tensor_t* const output_tensor = ccv_nnc_tensor_from_symbol(tensor_arena, output_symbol);
818 if (!output_tensor)
819 return;
820 const int d = output_symbol.d;
821 assert(d < tensor_init_states->compiled_data->tensors_init.size)((void) sizeof ((d < tensor_init_states->compiled_data->
tensors_init.size) ? 1 : 0), __extension__ ({ if (d < tensor_init_states
->compiled_data->tensors_init.size) ; else __assert_fail
("d < tensor_init_states->compiled_data->tensors_init.size"
, "ccv_cnnp_model.c", 821, __extension__ __PRETTY_FUNCTION__)
; }))
;
822 uint32_t* const init_v = CCV_NNC_INIT_V(tensor_init_states->compiled_data->tensors_init.v)((uint32_t*)((uintptr_t)(tensor_init_states->compiled_data
->tensors_init.v) & ~(uintptr_t)1))
;
823 if (init_v[d >> 5] & (1u << (d & 0x1f)))
824 return;
825 init_v[d >> 5] |= (1u << (d & 0x1f));
826 ccv_nnc_cmd_exec(cmd, hint, flags, &input, input ? 1 : 0, &output_tensor, 1, 0);
827 const ccv_nnc_symbolic_graph_t* const graph = tensor_init_states->graph;
828 const int parallel_count = tensor_init_states->parallel_count;
829 int i;
830 for (i = 1; i < parallel_count; i++)
831 {
832 ccv_nnc_tensor_t* const copy = ccv_nnc_tensor_from_symbol(tensor_arena, ccv_nnc_tensor_symbol_copy(graph, output_symbol, i));
833 if (copy)
834 ccv_nnc_cmd_exec(CMD_DATA_TRANSFER_FORWARD()ccv_nnc_cmd(CCV_NNC_DATA_TRANSFER_FORWARD, 0, ccv_nnc_cmd_auto
, 0)
, ccv_nnc_no_hint, 0, &output_tensor, 1, &copy, 1, 0);
835 }
836}
837
838// This method can only handle cases we added new tensors and exec, never delete. This invariant is true because
839// we setup everything (including calling simplify method) in ccv_cnnp_model_compile method, before this rewind setup.
840static void _ccv_cnnp_model_rewind_graph(ccv_cnnp_model_t* const model)
841{
842 assert(model->graph)((void) sizeof ((model->graph) ? 1 : 0), __extension__ ({ if
(model->graph) ; else __assert_fail ("model->graph", "ccv_cnnp_model.c"
, 842, __extension__ __PRETTY_FUNCTION__); }))
;
843 assert(model->compiled_data)((void) sizeof ((model->compiled_data) ? 1 : 0), __extension__
({ if (model->compiled_data) ; else __assert_fail ("model->compiled_data"
, "ccv_cnnp_model.c", 843, __extension__ __PRETTY_FUNCTION__)
; }))
;
844 ccv_cnnp_compiled_data_t* const compiled_data = model->compiled_data;
845 assert(compiled_data->rewindables)((void) sizeof ((compiled_data->rewindables) ? 1 : 0), __extension__
({ if (compiled_data->rewindables) ; else __assert_fail (
"compiled_data->rewindables", "ccv_cnnp_model.c", 845, __extension__
__PRETTY_FUNCTION__); }))
;
846 int i;
847 for (i = 0; i < compiled_data->rewindables->rnum; i++)
848 {
849 const ccv_cnnp_rewind_symbol_t* const rewind_symbol = (ccv_cnnp_rewind_symbol_t*)ccv_array_get(compiled_data->rewindables, i)((void*)(((char*)((compiled_data->rewindables)->data)) +
(size_t)(compiled_data->rewindables)->rsize * (size_t)
(i)))
;
850 if (rewind_symbol->type == CCV_CNNP_REWIND_GRAPH_EXEC)
851 ccv_nnc_graph_exec_symbol_free(model->graph, rewind_symbol->graph_exec);
852 else if (rewind_symbol->type == CCV_CNNP_REWIND_TENSOR)
853 ccv_nnc_tensor_symbol_free(model->graph, rewind_symbol->tensor);
854 }
855 ccv_array_clear(compiled_data->rewindables);
856 ccv_nnc_graph_exec_symbol_autogen(model->graph, 0, 0, CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
857}
858
859static void _ccv_cnnp_model_tensor_symbol_new_hook(void* context, const ccv_nnc_tensor_symbol_t symbol, const ccv_nnc_tensor_param_t info, const char* const name)
860{
861 const ccv_cnnp_rewind_symbol_t rewind_symbol = {
862 .type = CCV_CNNP_REWIND_TENSOR,
863 .tensor = symbol
864 };
865 ccv_array_t* const rewind_symbols = (ccv_array_t*)context;
866 ccv_array_push(rewind_symbols, &rewind_symbol);
867}
868
869static void _ccv_cnnp_model_tensor_symbol_alias_new_hook(void* context, const ccv_nnc_tensor_symbol_t symbol, const ccv_nnc_tensor_symbol_t from_symbol, const int ofs[CCV_NNC_MAX_DIM_ALLOC(12)], const int inc[CCV_NNC_MAX_DIM_ALLOC(12)], const ccv_nnc_tensor_param_t info, const char* const name)
870{
871 const ccv_cnnp_rewind_symbol_t rewind_symbol = {
872 .type = CCV_CNNP_REWIND_TENSOR,
873 .tensor = symbol
874 };
875 ccv_array_t* const rewind_symbols = (ccv_array_t*)context;
876 ccv_array_push(rewind_symbols, &rewind_symbol);
877}
878
879static void _ccv_cnnp_model_graph_exec_symbol_new_hook(void* context, const ccv_nnc_graph_exec_symbol_t symbol, const ccv_nnc_cmd_t cmd, const ccv_nnc_tensor_symbol_t* const inputs, const int input_size, const ccv_nnc_tensor_symbol_t* const outputs, const int output_size, const char* const name)
880{
881 const ccv_cnnp_rewind_symbol_t rewind_symbol = {
882 .type = CCV_CNNP_REWIND_GRAPH_EXEC,
883 .graph_exec = symbol
884 };
885 ccv_array_t* const rewind_symbols = (ccv_array_t*)context;
886 ccv_array_push(rewind_symbols, &rewind_symbol);
887}
888
889static void _ccv_cnnp_model_graph_symbol_exec_set_for_graph_exec_arena(const ccv_nnc_graph_exec_arena_t* const graph_exec_arena, const int parallel_count, const ccv_nnc_graph_exec_symbol_t exec_symbol, const ccv_nnc_cmd_t cmd, ccv_nnc_symbolic_graph_t* const symbolic_graph)
890{
891 ccv_nnc_graph_exec_t const update_exec = ccv_nnc_graph_exec_from_symbol(graph_exec_arena, exec_symbol);
892 if (!CCV_NO_GRAPH_EXEC(update_exec)((update_exec).graph == 0))
893 ccv_nnc_graph_exec_set(update_exec.graph, update_exec, cmd);
894 int i;
895 for (i = 1; i < parallel_count; i++)
896 {
897 ccv_nnc_graph_exec_symbol_t copy_symbol = ccv_nnc_graph_exec_symbol_copy(symbolic_graph, exec_symbol, i);
898 const ccv_nnc_graph_exec_t copy = ccv_nnc_graph_exec_from_symbol(graph_exec_arena, copy_symbol);
899 if (!CCV_NO_GRAPH_EXEC(copy)((copy).graph == 0))
900 ccv_nnc_graph_exec_set(copy.graph, copy, cmd);
901 }
902}
903
904static void _ccv_cnnp_model_graph_exec_symbol_set(ccv_nnc_symbolic_graph_t* const symbolic_graph, ccv_cnnp_compiled_data_t* const compiled_data, const int parallel_count, const ccv_nnc_graph_exec_symbol_t exec_symbol, const ccv_nnc_cmd_t cmd)
905{
906 assert(compiled_data)((void) sizeof ((compiled_data) ? 1 : 0), __extension__ ({ if
(compiled_data) ; else __assert_fail ("compiled_data", "ccv_cnnp_model.c"
, 906, __extension__ __PRETTY_FUNCTION__); }))
;
907 assert(symbolic_graph)((void) sizeof ((symbolic_graph) ? 1 : 0), __extension__ ({ if
(symbolic_graph) ; else __assert_fail ("symbolic_graph", "ccv_cnnp_model.c"
, 907, __extension__ __PRETTY_FUNCTION__); }))
;
908 ccv_nnc_graph_exec_symbol_set(symbolic_graph, exec_symbol, cmd);
909 int i;
910 for (i = 1; i < parallel_count; i++)
911 {
912 ccv_nnc_graph_exec_symbol_t copy_symbol = ccv_nnc_graph_exec_symbol_copy(symbolic_graph, exec_symbol, i);
913 if (copy_symbol.graph)
914 ccv_nnc_graph_exec_symbol_set(symbolic_graph, copy_symbol, cmd);
915 }
916 ccv_nnc_graph_exec_arena_t* const graph_exec_arena = compiled_data->graph_exec_arena;
917 if (graph_exec_arena)
918 _ccv_cnnp_model_graph_symbol_exec_set_for_graph_exec_arena(graph_exec_arena, parallel_count, exec_symbol, cmd, symbolic_graph);
919 // Skip backward graph exec arena because it is for a specific accum symbolic graph, not the main graph (model->graph)
920 ccv_nnc_graph_exec_arena_t* const gradient_graph_exec_arena = compiled_data->apply_gradients.graph_exec_arena;
921 if (gradient_graph_exec_arena)
922 _ccv_cnnp_model_graph_symbol_exec_set_for_graph_exec_arena(gradient_graph_exec_arena, parallel_count, exec_symbol, cmd, symbolic_graph);
923}
924
925static int _ccv_cnnp_set_minimizer_for_parameter(ccv_nnc_symbolic_graph_t* const graph, ccv_cnnp_compiled_data_t* const compiled_data, ccv_nnc_graph_exec_symbol_t* const update_nodes, ccv_nnc_tensor_symbol_t* const updated_parameters, ccv_nnc_tensor_symbol_map_t* const saved_aux, const int parallel_count, const ccv_nnc_cmd_t minimizer, const int saved_aux_size, const int max_saved_aux_size, const int parameter_indice)
926{
927 int this_parameter_flag = 0;
928 if (update_nodes[parameter_indice].d == CCV_NNC_NO_TENSOR_SYMBOL)
929 return this_parameter_flag;
930 const ccv_nnc_cmd_t old_minimizer = ccv_nnc_graph_exec_symbol_cmd(graph, update_nodes[parameter_indice]);
931 int j, k;
932 // For no-op, we can preserve previous saved_aux_size.
933 if (old_minimizer.cmd != minimizer.cmd && minimizer.cmd != CCV_NNC_NOOP)
934 {
935 // If the old minimizer is a noop, then the old_saved_aux_size should be whatever its previous
936 // saved_aux_size is, otherwise we will reinit the saved_aux repeatedly if you switch between
937 // noop and a minimizer. We don't want that because we do that in high-level frameworks to
938 // make sure some model parameters don't update if we don't want them to.
939 int old_saved_aux_size;
940 if (old_minimizer.cmd == CCV_NNC_NOOP)
941 {
942 int input_size;
943 ccv_nnc_graph_exec_symbol_io(graph, update_nodes[parameter_indice], 0, &input_size, 0, 0);
944 if (input_size < 2) // This is not legit.
945 old_saved_aux_size = ccv_nnc_minimizer_saved_aux_size(old_minimizer);
946 else // See ccv_nnc_minimizer_saved_aux_size, the saved_aux is inputs excluding gradients and parameters.
947 old_saved_aux_size = input_size - 2;
948 } else
949 old_saved_aux_size = ccv_nnc_minimizer_saved_aux_size(old_minimizer);
950 if (old_saved_aux_size != saved_aux_size)
951 {
952 this_parameter_flag = 1;
953 if (saved_aux_size > old_saved_aux_size)
954 {
955 // Allocate new tensor symbols.
956 const ccv_nnc_tensor_param_t info = ccv_nnc_tensor_symbol_params(graph, updated_parameters[parameter_indice]);
957 for (j = old_saved_aux_size; j < saved_aux_size; j++)
958 {
959 saved_aux[parameter_indice * max_saved_aux_size + j].source = ccv_nnc_tensor_symbol_new(graph, info, 0);
960 saved_aux[parameter_indice * max_saved_aux_size + j].destination = ccv_nnc_tensor_symbol_new(graph, info, 0);
961 const int device_id = CCV_TENSOR_GET_DEVICE_ID(info.type)(((info.type) & 0xfff00) >> 8);
962 for (k = 1; k < parallel_count; k++)
963 {
964 ccv_nnc_tensor_param_t dev_info = info;
965 if (k != device_id)
966 CCV_TENSOR_SET_DEVICE_ID(dev_info.type, k)(dev_info.type) = (((dev_info.type) & ~0xfff00) | (((k) &
0xfff) << 8))
;
967 else
968 CCV_TENSOR_SET_DEVICE_ID(dev_info.type, 0)(dev_info.type) = (((dev_info.type) & ~0xfff00) | (((0) &
0xfff) << 8))
;
969 const ccv_nnc_tensor_symbol_t src_copy = ccv_nnc_tensor_symbol_new(graph, dev_info, 0);
970 const ccv_nnc_tensor_symbol_t dest_copy = ccv_nnc_tensor_symbol_new(graph, dev_info, 0);
971 ccv_nnc_tensor_symbol_set_copy(graph, saved_aux[parameter_indice * max_saved_aux_size + j].source, k, src_copy);
972 ccv_nnc_tensor_symbol_set_copy(graph, saved_aux[parameter_indice * max_saved_aux_size + j].destination, k, dest_copy);
973 }
974 }
975 } else {
976 for (j = saved_aux_size; j < old_saved_aux_size; j++)
977 {
978 for (k = 1; k < parallel_count; k++)
979 {
980 const ccv_nnc_tensor_symbol_t src_copy = ccv_nnc_tensor_symbol_copy(graph, saved_aux[parameter_indice * max_saved_aux_size + j].source, k);
981 if (src_copy.d >= 0)
982 {
983 ccv_nnc_tensor_symbol_free(graph, src_copy);
984 ccv_nnc_tensor_symbol_set_copy(graph, saved_aux[parameter_indice * max_saved_aux_size + j].source, k, NO_TENSOR_SYMBOL(const ccv_nnc_tensor_symbol_t){.d = CCV_NNC_NO_TENSOR_SYMBOL
}
);
985 }
986 const ccv_nnc_tensor_symbol_t dest_copy = ccv_nnc_tensor_symbol_copy(graph, saved_aux[parameter_indice * max_saved_aux_size + j].destination, k);
987 if (dest_copy.d >= 0)
988 {
989 ccv_nnc_tensor_symbol_free(graph, dest_copy);
990 ccv_nnc_tensor_symbol_set_copy(graph, saved_aux[parameter_indice * max_saved_aux_size + j].destination, k, NO_TENSOR_SYMBOL(const ccv_nnc_tensor_symbol_t){.d = CCV_NNC_NO_TENSOR_SYMBOL
}
);
991 }
992 }
993 ccv_nnc_tensor_symbol_free(graph, saved_aux[parameter_indice * max_saved_aux_size + j].source);
994 ccv_nnc_tensor_symbol_free(graph, saved_aux[parameter_indice * max_saved_aux_size + j].destination);
995 saved_aux[parameter_indice * max_saved_aux_size + j].source = saved_aux[parameter_indice * max_saved_aux_size + j].destination = NO_TENSOR_SYMBOL(const ccv_nnc_tensor_symbol_t){.d = CCV_NNC_NO_TENSOR_SYMBOL
}
;
996 }
997 }
998 }
999 }
1000 _ccv_cnnp_model_graph_exec_symbol_set(graph, compiled_data, parallel_count, update_nodes[parameter_indice], minimizer);
1001 if (this_parameter_flag)
1002 {
1003 ccv_nnc_tensor_symbol_t update_inputs[saved_aux_size + 2];
1004 ccv_nnc_tensor_symbol_t update_outputs[saved_aux_size + 1];
1005 const int* inputs = 0;
1006 int input_size = 0;
1007 ccv_nnc_graph_exec_symbol_io(graph, update_nodes[parameter_indice], &inputs, &input_size, 0, 0);
1008 assert(input_size >= 1)((void) sizeof ((input_size >= 1) ? 1 : 0), __extension__ (
{ if (input_size >= 1) ; else __assert_fail ("input_size >= 1"
, "ccv_cnnp_model.c", 1008, __extension__ __PRETTY_FUNCTION__
); }))
;
1009 update_inputs[0].d = inputs[0];
1010 update_inputs[0].graph = graph;
1011 update_inputs[1].d = inputs[1];
1012 update_inputs[1].graph = graph;
1013 update_outputs[0] = updated_parameters[parameter_indice];
1014 for (j = 0; j < saved_aux_size; j++)
1015 {
1016 update_inputs[j + 2] = saved_aux[parameter_indice * max_saved_aux_size + j].source;
1017 update_outputs[j + 1] = saved_aux[parameter_indice * max_saved_aux_size + j].destination;
1018 }
1019 ccv_nnc_graph_exec_symbol_set_io(graph, update_nodes[parameter_indice], update_inputs, saved_aux_size + 2, update_outputs, saved_aux_size + 1);
1020 for (k = 1; k < parallel_count; k++)
1021 {
1022 const ccv_nnc_graph_exec_symbol_t copy = ccv_nnc_graph_exec_symbol_copy(graph, update_nodes[parameter_indice], k);
1023 assert(copy.d >= 0)((void) sizeof ((copy.d >= 0) ? 1 : 0), __extension__ ({ if
(copy.d >= 0) ; else __assert_fail ("copy.d >= 0", "ccv_cnnp_model.c"
, 1023, __extension__ __PRETTY_FUNCTION__); }))
;
1024 ccv_nnc_graph_exec_symbol_io(graph, copy, &inputs, &input_size, 0, 0);
1025 assert(input_size >= 1)((void) sizeof ((input_size >= 1) ? 1 : 0), __extension__ (
{ if (input_size >= 1) ; else __assert_fail ("input_size >= 1"
, "ccv_cnnp_model.c", 1025, __extension__ __PRETTY_FUNCTION__
); }))
;
1026 update_inputs[0].d = inputs[0];
1027 update_inputs[0].graph = graph;
1028 update_inputs[1].d = inputs[1];
1029 update_inputs[1].graph = graph;
1030 update_outputs[0] = ccv_nnc_tensor_symbol_copy(graph, updated_parameters[parameter_indice], k);
1031 for (j = 0; j < saved_aux_size; j++)
1032 {
1033 update_inputs[j + 2] = ccv_nnc_tensor_symbol_copy(graph, saved_aux[parameter_indice * max_saved_aux_size + j].source, k);
1034 update_outputs[j + 1] = ccv_nnc_tensor_symbol_copy(graph, saved_aux[parameter_indice * max_saved_aux_size + j].destination, k);
1035 }
1036 ccv_nnc_graph_exec_symbol_set_io(graph, copy, update_inputs, saved_aux_size + 2, update_outputs, saved_aux_size + 1);
1037 }
1038 }
1039 return this_parameter_flag;
1040}
1041
1042typedef struct {
1043 int parameter_size;
1044 ccv_nnc_cmd_t minimizer;
1045 ccv_cnnp_model_io_t parameters[1];
1046} ccv_cnnp_set_minimizer_for_parameter_t;
1047
1048static int _ccv_cnnp_apply_parameters_with_minimizer(ccv_cnnp_model_t* const model)
1049{
1050 ccv_cnnp_compiled_data_t* const compiled_data = model->compiled_data;
1051 assert(compiled_data)((void) sizeof ((compiled_data) ? 1 : 0), __extension__ ({ if
(compiled_data) ; else __assert_fail ("compiled_data", "ccv_cnnp_model.c"
, 1051, __extension__ __PRETTY_FUNCTION__); }))
;
1052 const int max_saved_aux_size = compiled_data->minimize.max_saved_aux_size;
1053 // We update all parameters, at this point, we have one minimizer.
1054 const int parameter_size = compiled_data->parameters->rnum;
1055 ccv_nnc_graph_exec_symbol_t* const update_nodes = compiled_data->update_nodes;
1056 ccv_nnc_symbolic_graph_t* const symbolic_graph = model->graph;
1057 assert(symbolic_graph)((void) sizeof ((symbolic_graph) ? 1 : 0), __extension__ ({ if
(symbolic_graph) ; else __assert_fail ("symbolic_graph", "ccv_cnnp_model.c"
, 1057, __extension__ __PRETTY_FUNCTION__); }))
;
1058 const int parallel_count = _ccv_cnnp_model_root_parallel_count(model);
1059 assert(_ccv_cnnp_model_effective_parallel_count(model) == parallel_count && "local replicated stateful models only support forward / no-grad evaluation for now")((void) sizeof ((_ccv_cnnp_model_effective_parallel_count(model
) == parallel_count && "local replicated stateful models only support forward / no-grad evaluation for now"
) ? 1 : 0), __extension__ ({ if (_ccv_cnnp_model_effective_parallel_count
(model) == parallel_count && "local replicated stateful models only support forward / no-grad evaluation for now"
) ; else __assert_fail ("_ccv_cnnp_model_effective_parallel_count(model) == parallel_count && \"local replicated stateful models only support forward / no-grad evaluation for now\""
, "ccv_cnnp_model.c", 1059, __extension__ __PRETTY_FUNCTION__
); }))
;
1060 ccv_array_t* const parameters = compiled_data->minimize.parameters;
1061 ccv_array_t* const parameter_indices = ccv_array_new(sizeof(int), 0, 0);
1062 int i, j, flag = 0;
1063 for (i = 0; i < parameters->rnum; i++)
1064 {
1065 ccv_cnnp_set_minimizer_for_parameter_t* const set_minimizer_for_parameter = *(ccv_cnnp_set_minimizer_for_parameter_t**)ccv_array_get(parameters, i)((void*)(((char*)((parameters)->data)) + (size_t)(parameters
)->rsize * (size_t)(i)))
;
1066 for (j = 0; j < set_minimizer_for_parameter->parameter_size; j++)
1067 {
1068 const int param_sel = set_minimizer_for_parameter->parameters[j]->param_sel > 0 ? set_minimizer_for_parameter->parameters[j]->param_sel - 1 : set_minimizer_for_parameter->parameters[j]->param_sel;
1069 assert(set_minimizer_for_parameter->parameters[j]->param_sel != 0)((void) sizeof ((set_minimizer_for_parameter->parameters[j
]->param_sel != 0) ? 1 : 0), __extension__ ({ if (set_minimizer_for_parameter
->parameters[j]->param_sel != 0) ; else __assert_fail (
"set_minimizer_for_parameter->parameters[j]->param_sel != 0"
, "ccv_cnnp_model.c", 1069, __extension__ __PRETTY_FUNCTION__
); }))
;
1070 const int old_rnum = parameter_indices->rnum;
1071 ccv_cnnp_model_add_to_parameter_indices(set_minimizer_for_parameter->parameters[j]->model, param_sel, parameter_indices);
1072 const int param_ref = set_minimizer_for_parameter->parameters[j]->param_ref > 0 ? set_minimizer_for_parameter->parameters[j]->param_ref - 1 : set_minimizer_for_parameter->parameters[j]->param_ref;
1073 assert(set_minimizer_for_parameter->parameters[j]->param_ref != 0)((void) sizeof ((set_minimizer_for_parameter->parameters[j
]->param_ref != 0) ? 1 : 0), __extension__ ({ if (set_minimizer_for_parameter
->parameters[j]->param_ref != 0) ; else __assert_fail (
"set_minimizer_for_parameter->parameters[j]->param_ref != 0"
, "ccv_cnnp_model.c", 1073, __extension__ __PRETTY_FUNCTION__
); }))
;
1074 if (param_ref >= 0)
1075 {
1076 assert(param_ref + old_rnum < parameter_indices->rnum)((void) sizeof ((param_ref + old_rnum < parameter_indices->
rnum) ? 1 : 0), __extension__ ({ if (param_ref + old_rnum <
parameter_indices->rnum) ; else __assert_fail ("param_ref + old_rnum < parameter_indices->rnum"
, "ccv_cnnp_model.c", 1076, __extension__ __PRETTY_FUNCTION__
); }))
;
1077 *(int*)ccv_array_get(parameter_indices, old_rnum)((void*)(((char*)((parameter_indices)->data)) + (size_t)(parameter_indices
)->rsize * (size_t)(old_rnum)))
= *(int*)ccv_array_get(parameter_indices, param_ref + old_rnum)((void*)(((char*)((parameter_indices)->data)) + (size_t)(parameter_indices
)->rsize * (size_t)(param_ref + old_rnum)))
;
1078 parameter_indices->rnum = old_rnum + 1;
1079 }
1080 }
1081 const int saved_aux_size = ccv_nnc_minimizer_saved_aux_size(set_minimizer_for_parameter->minimizer);
1082 // We may have duplicated indices, but that is OK, we will set it twice.
1083 for (j = 0; j < parameter_indices->rnum; j++)
1084 {
1085 const int d = *(int*)ccv_array_get(parameter_indices, j)((void*)(((char*)((parameter_indices)->data)) + (size_t)(parameter_indices
)->rsize * (size_t)(j)))
;
1086 assert(d <= parameter_size)((void) sizeof ((d <= parameter_size) ? 1 : 0), __extension__
({ if (d <= parameter_size) ; else __assert_fail ("d <= parameter_size"
, "ccv_cnnp_model.c", 1086, __extension__ __PRETTY_FUNCTION__
); }))
;
1087 if (_ccv_cnnp_set_minimizer_for_parameter(symbolic_graph, compiled_data, update_nodes, compiled_data->updated_parameters, compiled_data->saved_aux, parallel_count, set_minimizer_for_parameter->minimizer, saved_aux_size, max_saved_aux_size, d))
1088 flag = 1;
1089 }
1090 ccv_array_clear(parameter_indices);
1091 }
1092 ccv_array_free(parameter_indices);
1093 return flag;
1094}
1095
1096static void _ccv_cnnp_scatter_saved_aux(ccv_nnc_tensor_symbol_map_t* const saved_aux, const int parameter_size, const int old_saved_aux_size, const int new_saved_aux_size)
1097{
1098 if (new_saved_aux_size == old_saved_aux_size)
1099 return;
1100 assert(new_saved_aux_size > old_saved_aux_size)((void) sizeof ((new_saved_aux_size > old_saved_aux_size) ?
1 : 0), __extension__ ({ if (new_saved_aux_size > old_saved_aux_size
) ; else __assert_fail ("new_saved_aux_size > old_saved_aux_size"
, "ccv_cnnp_model.c", 1100, __extension__ __PRETTY_FUNCTION__
); }))
;
1101 int i, j;
1102 for (i = parameter_size - 1; i >= 0; i--)
1103 {
1104 for (j = new_saved_aux_size - 1; j >= old_saved_aux_size; j--)
1105 saved_aux[i * new_saved_aux_size + j].source = saved_aux[i * new_saved_aux_size + j].destination = NO_TENSOR_SYMBOL(const ccv_nnc_tensor_symbol_t){.d = CCV_NNC_NO_TENSOR_SYMBOL
}
;
1106 for (j = old_saved_aux_size - 1; j >= 0; j--)
1107 saved_aux[i * new_saved_aux_size + j] = saved_aux[i * old_saved_aux_size + j];
1108 }
1109}
1110
1111static void _ccv_cnnp_model_set_rewindables(ccv_cnnp_model_t* const model)
1112{
1113 ccv_cnnp_compiled_data_t* const compiled_data = model->compiled_data;
1114 assert(compiled_data)((void) sizeof ((compiled_data) ? 1 : 0), __extension__ ({ if
(compiled_data) ; else __assert_fail ("compiled_data", "ccv_cnnp_model.c"
, 1114, __extension__ __PRETTY_FUNCTION__); }))
;
1115 if (!compiled_data->rewindables)
1116 compiled_data->rewindables = ccv_array_new(sizeof(ccv_cnnp_rewind_symbol_t), 0, 0);
1117 ccv_nnc_tensor_symbol_new_hook(model->graph, _ccv_cnnp_model_tensor_symbol_new_hook, compiled_data->rewindables, 0);
1118 ccv_nnc_tensor_symbol_alias_new_hook(model->graph, _ccv_cnnp_model_tensor_symbol_alias_new_hook, compiled_data->rewindables, 0);
1119 ccv_nnc_graph_exec_symbol_new_hook(model->graph, _ccv_cnnp_model_graph_exec_symbol_new_hook, compiled_data->rewindables, 0);
1120}
1121
1122static void _ccv_cnnp_model_gradient_init(ccv_cnnp_model_t* const model, const int gradient_mode, const uint64_t disable_outgrad, ccv_nnc_tensor_t* const* const fits, const int fit_size)
1123{
1124 ccv_cnnp_compiled_data_t* const compiled_data = model->compiled_data;
1125 assert(compiled_data->gradient_mode == CCV_CNNP_COMPILED_DATA_GRADIENT_NONE)((void) sizeof ((compiled_data->gradient_mode == CCV_CNNP_COMPILED_DATA_GRADIENT_NONE
) ? 1 : 0), __extension__ ({ if (compiled_data->gradient_mode
== CCV_CNNP_COMPILED_DATA_GRADIENT_NONE) ; else __assert_fail
("compiled_data->gradient_mode == CCV_CNNP_COMPILED_DATA_GRADIENT_NONE"
, "ccv_cnnp_model.c", 1125, __extension__ __PRETTY_FUNCTION__
); }))
;
1126 assert(gradient_mode != CCV_CNNP_COMPILED_DATA_GRADIENT_NONE)((void) sizeof ((gradient_mode != CCV_CNNP_COMPILED_DATA_GRADIENT_NONE
) ? 1 : 0), __extension__ ({ if (gradient_mode != CCV_CNNP_COMPILED_DATA_GRADIENT_NONE
) ; else __assert_fail ("gradient_mode != CCV_CNNP_COMPILED_DATA_GRADIENT_NONE"
, "ccv_cnnp_model.c", 1126, __extension__ __PRETTY_FUNCTION__
); }))
;
1127 const int evaluate_to_size = compiled_data->evaluate.to_size;
1128 assert(evaluate_to_size > 0)((void) sizeof ((evaluate_to_size > 0) ? 1 : 0), __extension__
({ if (evaluate_to_size > 0) ; else __assert_fail ("evaluate_to_size > 0"
, "ccv_cnnp_model.c", 1128, __extension__ __PRETTY_FUNCTION__
); }))
;
1129 const int parallel_count = _ccv_cnnp_model_root_parallel_count(model);
1130 assert(_ccv_cnnp_model_effective_parallel_count(model) == parallel_count && "local replicated stateful models only support forward / no-grad evaluation for now")((void) sizeof ((_ccv_cnnp_model_effective_parallel_count(model
) == parallel_count && "local replicated stateful models only support forward / no-grad evaluation for now"
) ? 1 : 0), __extension__ ({ if (_ccv_cnnp_model_effective_parallel_count
(model) == parallel_count && "local replicated stateful models only support forward / no-grad evaluation for now"
) ; else __assert_fail ("_ccv_cnnp_model_effective_parallel_count(model) == parallel_count && \"local replicated stateful models only support forward / no-grad evaluation for now\""
, "ccv_cnnp_model.c", 1130, __extension__ __PRETTY_FUNCTION__
); }))
;
1131 compiled_data->evaluate.tos = ccreallocrealloc(compiled_data->evaluate.tos, sizeof(ccv_nnc_graph_exec_symbol_t) * evaluate_to_size * parallel_count + sizeof(ccv_nnc_graph_exec_t) * evaluate_to_size * parallel_count);
1132 compiled_data->evaluate.to_ops = (ccv_nnc_graph_exec_t*)(compiled_data->evaluate.tos + evaluate_to_size * parallel_count);
1133 int i, j;
1134 const int output_size = model->output_size;
1135 assert(!fits || fit_size == output_size * parallel_count)((void) sizeof ((!fits || fit_size == output_size * parallel_count
) ? 1 : 0), __extension__ ({ if (!fits || fit_size == output_size
* parallel_count) ; else __assert_fail ("!fits || fit_size == output_size * parallel_count"
, "ccv_cnnp_model.c", 1135, __extension__ __PRETTY_FUNCTION__
); }))
;
1136 if (fits)
1137 for (i = 0; i < output_size; i++)
1138 ccv_nnc_tensor_symbol_set(model->graph, compiled_data->fits[i], fits[i]->info);
1139 const int max_saved_aux_size = compiled_data->minimize.max_saved_aux_size;
1140 const int parameter_size = compiled_data->parameters->rnum;
1141 compiled_data->updated_parameters = (ccv_nnc_tensor_symbol_t*)ccmallocmalloc(sizeof(ccv_nnc_tensor_symbol_t) * parameter_size + sizeof(ccv_nnc_graph_exec_symbol_t) * parameter_size + sizeof(ccv_nnc_tensor_symbol_map_t) * max_saved_aux_size * parameter_size);
1142 compiled_data->update_nodes = (ccv_nnc_graph_exec_symbol_t*)(compiled_data->updated_parameters + parameter_size);
1143 compiled_data->saved_aux = (ccv_nnc_tensor_symbol_map_t*)(compiled_data->update_nodes + parameter_size);
1144 int parameter_size_maybe_more = parameter_size;
1145 compiled_data->disable_outgrad = disable_outgrad;
1146 int outgrad_size;
1147 if (gradient_mode == CCV_CNNP_COMPILED_DATA_GRADIENT_TRAINABLES || model->input_size == 0)
1148 outgrad_size = 0;
1149 else if (disable_outgrad == CCV_CNNP_DISABLE_OUTGRAD_NONE) // Compute minimize with gradients including inputs.
1150 outgrad_size = model->input_size;
1151 else {
1152 assert(disable_outgrad != CCV_CNNP_DISABLE_OUTGRAD_ALL)((void) sizeof ((disable_outgrad != CCV_CNNP_DISABLE_OUTGRAD_ALL
) ? 1 : 0), __extension__ ({ if (disable_outgrad != CCV_CNNP_DISABLE_OUTGRAD_ALL
) ; else __assert_fail ("disable_outgrad != CCV_CNNP_DISABLE_OUTGRAD_ALL"
, "ccv_cnnp_model.c", 1152, __extension__ __PRETTY_FUNCTION__
); }))
; // If it is disable all, gradient mode won't be this.
1153 outgrad_size = 0;
1154 for (i = 0; i < model->input_size; i++)
1155 if (!(disable_outgrad & ((uint64_t)1 << i)))
1156 ++outgrad_size;
1157 }
1158 compiled_data->outgrad_size = outgrad_size;
1159 parameter_size_maybe_more += outgrad_size;
1160 compiled_data->gradients = (ccv_nnc_tensor_symbol_t*)ccmallocmalloc(sizeof(ccv_nnc_tensor_symbol_t) * parameter_size_maybe_more + sizeof(ccv_nnc_graph_exec_symbol_t) * parameter_size_maybe_more * parallel_count);
1161 compiled_data->outgrads = parameter_size_maybe_more > parameter_size ? compiled_data->gradients + parameter_size : 0;
1162 compiled_data->backward.tos = (ccv_nnc_graph_exec_symbol_t*)(compiled_data->gradients + parameter_size_maybe_more);
1163 compiled_data->backward.to_size = parameter_size_maybe_more;
1164 ccv_nnc_tensor_symbol_t* parameters = (ccv_nnc_tensor_symbol_t*)ccv_array_get(compiled_data->parameters, 0)((void*)(((char*)((compiled_data->parameters)->data)) +
(size_t)(compiled_data->parameters)->rsize * (size_t)(
0)))
;
1165 if (compiled_data->parameter_flags)
1166 {
1167 parameters = (ccv_nnc_tensor_symbol_t*)ccmallocmalloc(sizeof(ccv_nnc_tensor_symbol_t) * parameter_size);
1168 for (i = 0; i < parameter_size; i++)
1169 if (compiled_data->parameter_flags[i >> 6] & ((uint64_t)1 << (i & 63)))
1170 parameters[i] = *(ccv_nnc_tensor_symbol_t*)ccv_array_get(compiled_data->parameters, i)((void*)(((char*)((compiled_data->parameters)->data)) +
(size_t)(compiled_data->parameters)->rsize * (size_t)(
i)))
;
1171 else
1172 parameters[i] = NO_TENSOR_SYMBOL(const ccv_nnc_tensor_symbol_t){.d = CCV_NNC_NO_TENSOR_SYMBOL
}
;
1173 }
1174 if (gradient_mode == CCV_CNNP_COMPILED_DATA_GRADIENT_TRAINABLES || model->input_size == 0)
1175 ccv_nnc_symbolic_graph_minimize(model->graph, compiled_data->minimize.minimizer, compiled_data->f, output_size, parameters, parameter_size, 0, 0, SYMBOLIC_GRAPH_SOURCES(model->graph)ccv_nnc_symbolic_graph_sources(model->graph), ccv_nnc_symbolic_graph_source_size
(model->graph)
, SYMBOLIC_GRAPH_DESTINATIONS(model->graph)ccv_nnc_symbolic_graph_destinations(model->graph), ccv_nnc_symbolic_graph_destination_size
(model->graph)
, compiled_data->gradients, compiled_data->updated_parameters, compiled_data->saved_aux, compiled_data->update_nodes);
1176 else if (disable_outgrad == CCV_CNNP_DISABLE_OUTGRAD_NONE) // Compute minimize with gradients including inputs.
1177 ccv_nnc_symbolic_graph_minimize(model->graph, compiled_data->minimize.minimizer, compiled_data->f, output_size, parameters, parameter_size, model->inputs, model->input_size, SYMBOLIC_GRAPH_SOURCES(model->graph)ccv_nnc_symbolic_graph_sources(model->graph), ccv_nnc_symbolic_graph_source_size
(model->graph)
, SYMBOLIC_GRAPH_DESTINATIONS(model->graph)ccv_nnc_symbolic_graph_destinations(model->graph), ccv_nnc_symbolic_graph_destination_size
(model->graph)
, compiled_data->gradients, compiled_data->updated_parameters, compiled_data->saved_aux, compiled_data->update_nodes);
1178 else { // Compute minimize with gradients including selected inputs.
1179 assert(model->input_size > 0)((void) sizeof ((model->input_size > 0) ? 1 : 0), __extension__
({ if (model->input_size > 0) ; else __assert_fail ("model->input_size > 0"
, "ccv_cnnp_model.c", 1179, __extension__ __PRETTY_FUNCTION__
); }))
;
1180 assert(disable_outgrad != CCV_CNNP_DISABLE_OUTGRAD_ALL)((void) sizeof ((disable_outgrad != CCV_CNNP_DISABLE_OUTGRAD_ALL
) ? 1 : 0), __extension__ ({ if (disable_outgrad != CCV_CNNP_DISABLE_OUTGRAD_ALL
) ; else __assert_fail ("disable_outgrad != CCV_CNNP_DISABLE_OUTGRAD_ALL"
, "ccv_cnnp_model.c", 1180, __extension__ __PRETTY_FUNCTION__
); }))
; // If it is disable all, gradient mode won't be this.
1181 assert(outgrad_size > 0)((void) sizeof ((outgrad_size > 0) ? 1 : 0), __extension__
({ if (outgrad_size > 0) ; else __assert_fail ("outgrad_size > 0"
, "ccv_cnnp_model.c", 1181, __extension__ __PRETTY_FUNCTION__
); }))
;
1182 ccv_nnc_tensor_symbol_t outgrads[outgrad_size];
1183 j = 0;
1184 for (i = 0; i < model->input_size; i++)
1185 if (!(disable_outgrad & ((uint64_t)1 << i)))
1186 outgrads[j++] = model->inputs[i];
1187 ccv_nnc_symbolic_graph_minimize(model->graph, compiled_data->minimize.minimizer, compiled_data->f, output_size, parameters, parameter_size, outgrads, outgrad_size, SYMBOLIC_GRAPH_SOURCES(model->graph)ccv_nnc_symbolic_graph_sources(model->graph), ccv_nnc_symbolic_graph_source_size
(model->graph)
, SYMBOLIC_GRAPH_DESTINATIONS(model->graph)ccv_nnc_symbolic_graph_destinations(model->graph), ccv_nnc_symbolic_graph_destination_size
(model->graph)
, compiled_data->gradients, compiled_data->updated_parameters, compiled_data->saved_aux, compiled_data->update_nodes);
1188 }
1189 if (compiled_data->parameter_flags)
1190 ccfreefree(parameters);
1191 _ccv_cnnp_scatter_saved_aux(compiled_data->saved_aux, parameter_size, ccv_nnc_minimizer_saved_aux_size(compiled_data->minimize.minimizer), compiled_data->minimize.max_saved_aux_size);
1192 if (compiled_data->minimize.parameters)
1193 _ccv_cnnp_apply_parameters_with_minimizer(model);
1194 // Go through gradient checkpoints to generate tensor inputs for backward pass just before executing the backward pass.
1195 ccv_cnnp_model_apply_gradient_checkpoints(compiled_data, model->graph);
1196 for (i = 0; i < output_size; i++)
1197 {
1198 const ccv_nnc_tensor_symbol_t df = ccv_nnc_tensor_symbol_for_backward(model->graph, compiled_data->f[i]);
1199 // Init this to 1 so we can backprop.
1200 ccv_nnc_tensor_symbol_set_flags(model->graph, df, CCV_NNC_TENSOR_SYMBOL_INIT_ONES);
1201 }
1202 compiled_data->backward.to_size = 0;
1203 for (i = 0; i < parameter_size_maybe_more; i++)
1204 if (compiled_data->gradients[i].d != CCV_NNC_NO_TENSOR_SYMBOL)
1205 compiled_data->backward.tos[compiled_data->backward.to_size++] = ccv_nnc_graph_exec_symbol_for_backward(model->graph, compiled_data->gradients[i]);
1206 ccv_nnc_graph_exec_symbol_autogen(model->graph, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS);
1207 ccv_nnc_symbolic_graph_set_destinations(model->graph, compiled_data->update_nodes, parameter_size);
1208 for (i = 0; i < parameter_size_maybe_more - parameter_size; i++)
1209 {
1210 if (compiled_data->outgrads[i].d < 0) // When we go through input, we might find zero-length inputs, and for these, we cannot have any outgrads.
1211 continue;
1212 const ccv_nnc_graph_exec_symbol_t outgrad = ccv_nnc_graph_exec_symbol_for_backward(model->graph, compiled_data->outgrads[i]);
1213 const int* tos;
1214 int to_size;
1215 ccv_nnc_graph_exec_symbol_to(model->graph, outgrad, &tos, &to_size);
1216 if (to_size == 0) // If this is the end (no minimizers afterwards). We need to attach this as a destination. Otherwise this is covered in update_nodes.
1217 {
1218 const ccv_nnc_graph_exec_symbol_t* destinations = ccv_nnc_symbolic_graph_destinations(model->graph);
1219 const int destination_count = ccv_nnc_symbolic_graph_destination_size(model->graph);
1220 int flag = 0;
1221 const int outgrad_destination_start = ccv_max(0, destination_count - i)({ typeof (0) _a = (0); typeof (destination_count - i) _b = (
destination_count - i); (_a > _b) ? _a : _b; })
;
1222 for (j = i - 1; !flag && j >= 0; j--)
1223 if (j + outgrad_destination_start < destination_count)
1224 flag = (destinations[j + outgrad_destination_start].d == outgrad.d);
1225 if (!flag) // Only if we cannot find it, we add it.
1226 ccv_nnc_symbolic_graph_add_destination(model->graph, outgrad);
1227 }
1228 }
1229 if (parallel_count > 1)
1230 {
1231 ccv_nnc_symbolic_graph_data_parallel(model->graph, parallel_count,
1232 0, 0,
1233 compiled_data->gradients, parameter_size /* No need to deal with outgrads, we don't allreduce outgrads */,
1234 compiled_data->gradients /* We only care about gradients before allreduce, thus, update our current pointers */,
1235 0, 0, 0,
1236 CCV_NNC_PARALLEL_REDUCE_OP_SUM,
1237 SYMBOLIC_GRAPH_SOURCES(model->graph)ccv_nnc_symbolic_graph_sources(model->graph), ccv_nnc_symbolic_graph_source_size
(model->graph)
, SYMBOLIC_GRAPH_DESTINATIONS(model->graph)ccv_nnc_symbolic_graph_destinations(model->graph), ccv_nnc_symbolic_graph_destination_size
(model->graph)
);
1238 ccv_nnc_graph_exec_symbol_autogen(model->graph, 0, 0, CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
1239 for (i = 0; i < evaluate_to_size; i++)
1240 for (j = 1; j < parallel_count; j++)
1241 {
1242 const ccv_nnc_graph_exec_symbol_t copy = ccv_nnc_graph_exec_symbol_copy(model->graph, compiled_data->evaluate.tos[i], j);
1243 if (copy.d != CCV_NNC_NO_GRAPH_EXEC_SYMBOL)
1244 compiled_data->evaluate.tos[compiled_data->evaluate.to_size++] = copy;
1245 }
1246 const int backward_to_size = compiled_data->backward.to_size;
1247 for (i = 0; i < backward_to_size; i++)
1248 for (j = 1; j < parallel_count; j++)
1249 {
1250 const ccv_nnc_graph_exec_symbol_t copy = ccv_nnc_graph_exec_symbol_copy(model->graph, compiled_data->backward.tos[i], j);
1251 if (copy.d != CCV_NNC_NO_GRAPH_EXEC_SYMBOL)
1252 compiled_data->backward.tos[compiled_data->backward.to_size++] = copy;
1253 }
1254 }
1255 // Only use memory compression if we are in gradient parameter mode.
1256 if (gradient_mode == CCV_CNNP_COMPILED_DATA_GRADIENT_TRAINABLES || gradient_mode == CCV_CNNP_COMPILED_DATA_GRADIENT_TRAINABLES_AND_INPUTS)
1257 {
1258 if (model->memory_compression)
1259 ccv_nnc_symbolic_graph_memory_compression(model->graph, SYMBOLIC_GRAPH_SOURCES(model->graph)ccv_nnc_symbolic_graph_sources(model->graph), ccv_nnc_symbolic_graph_source_size
(model->graph)
, SYMBOLIC_GRAPH_DESTINATIONS(model->graph)ccv_nnc_symbolic_graph_destinations(model->graph), ccv_nnc_symbolic_graph_destination_size
(model->graph)
);
1260 if (model->memory_reduction)
1261 ccv_nnc_symbolic_graph_memory_reduction(model->graph, SYMBOLIC_GRAPH_SOURCES(model->graph)ccv_nnc_symbolic_graph_sources(model->graph), ccv_nnc_symbolic_graph_source_size
(model->graph)
, SYMBOLIC_GRAPH_DESTINATIONS(model->graph)ccv_nnc_symbolic_graph_destinations(model->graph), ccv_nnc_symbolic_graph_destination_size
(model->graph)
);
1262 }
1263 compiled_data->backward.to_size = _ccv_nnc_array_dedup_graph_exec_symbols(compiled_data->backward.tos, compiled_data->backward.to_size);
1264 compiled_data->gradient_mode = gradient_mode;
1265}
1266
1267void ccv_cnnp_model_tensors_init_0(const ccv_cnnp_model_t* const model, ccv_cnnp_compiled_data_t* const compiled_data)
1268{
1269 assert(!compiled_data->tensors.parameters)((void) sizeof ((!compiled_data->tensors.parameters) ? 1 :
0), __extension__ ({ if (!compiled_data->tensors.parameters
) ; else __assert_fail ("!compiled_data->tensors.parameters"
, "ccv_cnnp_model.c", 1269, __extension__ __PRETTY_FUNCTION__
); }))
;
1270 const int parameter_size = compiled_data->parameters->rnum;
1271 const int parallel_count = _ccv_cnnp_model_effective_parallel_count(model);
1272 compiled_data->parallel_count = parallel_count;
1273 const int internal_size = compiled_data->internals->rnum;
1274 compiled_data->tensors_init.size = ccv_nnc_tensor_symbol_count(model->graph);
1275 compiled_data->tensors_init.v = cccalloccalloc(((compiled_data->tensors_init.size + 31) >> 5), sizeof(uint32_t));
1276 compiled_data->tensors.parameters = (ccv_nnc_tensor_t**)cccalloccalloc((parameter_size + internal_size) * parallel_count, sizeof(ccv_nnc_tensor_t*));
1277 compiled_data->tensors.internals = compiled_data->tensors.parameters + parameter_size * parallel_count;
1278}
1279
1280int ccv_cnnp_model_tensors_any_to_alloc(const ccv_cnnp_model_t* const model, ccv_cnnp_compiled_data_t* const compiled_data)
1281{
1282 int i, j;
1283 const int parameter_size = compiled_data->parameters->rnum;
1284 const int parallel_count = _ccv_cnnp_compiled_data_parallel_count(model, compiled_data);
1285 const int internal_size = compiled_data->internals->rnum;
1286 for (i = 0; i < parameter_size; i++)
1287 {
1288 // parameters has to be allocated all together.
1289 if (compiled_data->tensors.parameters[i])
1290 {
1291 for (j = 1; j < parallel_count; j++)
1292 { assert(compiled_data->tensors.parameters[i + j * parameter_size])((void) sizeof ((compiled_data->tensors.parameters[i + j *
parameter_size]) ? 1 : 0), __extension__ ({ if (compiled_data
->tensors.parameters[i + j * parameter_size]) ; else __assert_fail
("compiled_data->tensors.parameters[i + j * parameter_size]"
, "ccv_cnnp_model.c", 1292, __extension__ __PRETTY_FUNCTION__
); }))
; }
1293 continue;
1294 }
1295 return 1;
1296 }
1297 for (i = 0; i < internal_size; i++)
1298 {
1299 if (!compiled_data->tensors.internals[i])
1300 return 1;
1301 for (j = 1; j < parallel_count; j++)
1302 if (!compiled_data->tensors.internals[i + j * internal_size])
1303 return 1;
1304 }
1305 return 0;
1306}
1307
1308void ccv_cnnp_model_tensors_init_1(const ccv_cnnp_model_t* const model, ccv_cnnp_compiled_data_t* const compiled_data)
1309{
1310 int i, j;
1311 const int parameter_size = compiled_data->parameters->rnum;
1312 const int parallel_count = _ccv_cnnp_compiled_data_parallel_count(model, compiled_data);
1313 compiled_data->parallel_count = parallel_count;
1314 const int internal_size = compiled_data->internals->rnum;
1315 for (i = 0; i < parameter_size; i++)
1316 {
1317 // parameters has to be allocated all together.
1318 if (compiled_data->tensors.parameters[i])
1319 {
1320 for (j = 1; j < parallel_count; j++)
1321 { assert(compiled_data->tensors.parameters[i + j * parameter_size])((void) sizeof ((compiled_data->tensors.parameters[i + j *
parameter_size]) ? 1 : 0), __extension__ ({ if (compiled_data
->tensors.parameters[i + j * parameter_size]) ; else __assert_fail
("compiled_data->tensors.parameters[i + j * parameter_size]"
, "ccv_cnnp_model.c", 1321, __extension__ __PRETTY_FUNCTION__
); }))
; }
1322 continue;
1323 }
1324 const ccv_nnc_tensor_symbol_t parameter = *(ccv_nnc_tensor_symbol_t*)ccv_array_get(compiled_data->parameters, i)((void*)(((char*)((compiled_data->parameters)->data)) +
(size_t)(compiled_data->parameters)->rsize * (size_t)(
i)))
;
1325 ccv_nnc_tensor_param_t info = ccv_nnc_tensor_symbol_params(parameter.graph, parameter);
1326 if (CCV_TENSOR_GET_DEVICE(info.type)((info.type) & 0xfff00) == CCV_COMPUTE_DEVICE_ANY)
1327 CCV_TENSOR_SET_DEVICE_ID(info.type, 0)(info.type) = (((info.type) & ~0xfff00) | (((0) & 0xfff
) << 8))
;
1328 const int device_id = CCV_TENSOR_GET_DEVICE_ID(info.type)(((info.type) & 0xfff00) >> 8);
1329 compiled_data->tensors.parameters[i] = ccv_nnc_tensor_new(0, info, 0);
1330 for (j = 1; j < parallel_count; j++)
1331 {
1332 if (j != device_id)
1333 CCV_TENSOR_SET_DEVICE_ID(info.type, j)(info.type) = (((info.type) & ~0xfff00) | (((j) & 0xfff
) << 8))
;
1334 else
1335 CCV_TENSOR_SET_DEVICE_ID(info.type, 0)(info.type) = (((info.type) & ~0xfff00) | (((0) & 0xfff
) << 8))
;
1336 compiled_data->tensors.parameters[i + j * parameter_size] = ccv_nnc_tensor_new(0, info, 0);
1337 }
1338 }
1339 const uint32_t* const init_v = CCV_NNC_INIT_V(compiled_data->tensors_init.v)((uint32_t*)((uintptr_t)(compiled_data->tensors_init.v) &
~(uintptr_t)1))
;
1340 for (i = 0; i < internal_size; i++)
1341 {
1342 const ccv_nnc_tensor_symbol_t retained = *(ccv_nnc_tensor_symbol_t*)ccv_array_get(compiled_data->internals, i)((void*)(((char*)((compiled_data->internals)->data)) + (
size_t)(compiled_data->internals)->rsize * (size_t)(i))
)
;
1343 const int d = retained.d;
1344 if (init_v[d >> 5] & (1u << (d & 0x1f)))
1345 continue;
1346 ccv_nnc_tensor_param_t info = ccv_nnc_tensor_symbol_params(retained.graph, retained);
1347 if (CCV_TENSOR_GET_DEVICE(info.type)((info.type) & 0xfff00) == CCV_COMPUTE_DEVICE_ANY)
1348 CCV_TENSOR_SET_DEVICE_ID(info.type, 0)(info.type) = (((info.type) & ~0xfff00) | (((0) & 0xfff
) << 8))
;
1349 const int device_id = CCV_TENSOR_GET_DEVICE_ID(info.type)(((info.type) & 0xfff00) >> 8);
1350 if (!compiled_data->tensors.internals[i])
1351 compiled_data->tensors.internals[i] = ccv_nnc_tensor_new(0, info, 0);
1352 for (j = 1; j < parallel_count; j++)
1353 {
1354 if (j != device_id)
1355 CCV_TENSOR_SET_DEVICE_ID(info.type, j)(info.type) = (((info.type) & ~0xfff00) | (((j) & 0xfff
) << 8))
;
1356 else
1357 CCV_TENSOR_SET_DEVICE_ID(info.type, 0)(info.type) = (((info.type) & ~0xfff00) | (((0) & 0xfff
) << 8))
;
1358 if (!compiled_data->tensors.internals[i + j * internal_size])
1359 compiled_data->tensors.internals[i + j * internal_size] = ccv_nnc_tensor_new(0, info, 0);
1360 }
1361 }
1362 compiled_data->tensors_init.v = CCV_NNC_INIT_V(compiled_data->tensors_init.v)((uint32_t*)((uintptr_t)(compiled_data->tensors_init.v) &
~(uintptr_t)1))
; // Remove 1 if any.
1363}
1364
1365static void _ccv_cnnp_model_tensors_init(const ccv_cnnp_model_t* const model, ccv_cnnp_compiled_data_t* const compiled_data)
1366{
1367 ccv_cnnp_model_tensors_init_0(model, compiled_data);
1368 ccv_cnnp_model_tensors_init_1(model, compiled_data);
1369}
1370
1371static void _ccv_cnnp_model_copy_tensors(const uint32_t* const tensors_init, const ccv_nnc_tensor_symbol_t* const tensor_symbols, ccv_nnc_tensor_t* const* const tensors, const int tensor_size, const int parallel_count)
1372{
1373 assert(parallel_count > 0)((void) sizeof ((parallel_count > 0) ? 1 : 0), __extension__
({ if (parallel_count > 0) ; else __assert_fail ("parallel_count > 0"
, "ccv_cnnp_model.c", 1373, __extension__ __PRETTY_FUNCTION__
); }))
;
1374 int i, j;
1375 for (i = 0; i < tensor_size; i++)
1376 {
1377 if (!tensors[i])
1378 continue;
1379 const int d = tensor_symbols[i].d;
1380 if (!(tensors_init[d >> 5] & (1u << (d & 0x1f))))
1381 continue;
1382 for (j = 1; j < parallel_count; j++)
1383 if (tensors[i + j * tensor_size])
1384 {
1385 ccv_nnc_tensor_t* const input = CCV_NNC_TENSOR(tensors[i])((ccv_nnc_tensor_t*)((uintptr_t)(tensors[i]) & ~(uintptr_t
)1))
;
1386 ccv_nnc_tensor_t* const output = CCV_NNC_TENSOR(tensors[i + j * tensor_size])((ccv_nnc_tensor_t*)((uintptr_t)(tensors[i + j * tensor_size]
) & ~(uintptr_t)1))
;
1387 ccv_nnc_cmd_exec(CMD_DATA_TRANSFER_FORWARD()ccv_nnc_cmd(CCV_NNC_DATA_TRANSFER_FORWARD, 0, ccv_nnc_cmd_auto
, 0)
, ccv_nnc_no_hint, 0, &input, 1, &output, 1, 0);
1388 }
1389 }
1390}
1391
1392static void _ccv_cnnp_model_remove_nocopies(const ccv_nnc_symbolic_graph_t* const graph, const ccv_nnc_tensor_symbol_t* const tensor_symbols, ccv_nnc_tensor_t** const tensors, const int tensor_size, const int parallel_count)
1393{
1394 assert(parallel_count > 0)((void) sizeof ((parallel_count > 0) ? 1 : 0), __extension__
({ if (parallel_count > 0) ; else __assert_fail ("parallel_count > 0"
, "ccv_cnnp_model.c", 1394, __extension__ __PRETTY_FUNCTION__
); }))
;
1395 int i, j;
1396 for (i = 0; i < tensor_size; i++)
1397 {
1398 const ccv_nnc_tensor_symbol_t tensor_symbol = tensor_symbols[i];
1399 for (j = 1; j < parallel_count; j++)
1400 {
1401 const ccv_nnc_tensor_symbol_t copy = ccv_nnc_tensor_symbol_copy(graph, tensor_symbol, j);
1402 ccv_nnc_tensor_t* copy_tensor = tensors[i + j * tensor_size];
1403 if (copy_tensor && copy.d == CCV_NNC_NO_TENSOR_SYMBOL)
1404 { // We shouldn't allocate this, free it up.
1405 ccv_nnc_tensor_free(tensors[i + j * tensor_size]);
1406 tensors[i + j * tensor_size] = 0;
1407 }
1408 }
1409 }
1410}
1411
1412static void _ccv_cnnp_model_bind_tensors(const ccv_nnc_symbolic_graph_t* const graph, const ccv_nnc_tensor_symbol_t* const tensor_symbols, ccv_nnc_tensor_t* const* const tensors, const int tensor_size, const int parallel_count, ccv_array_t* const tensor_binds)
1413{
1414 assert(parallel_count > 0)((void) sizeof ((parallel_count > 0) ? 1 : 0), __extension__
({ if (parallel_count > 0) ; else __assert_fail ("parallel_count > 0"
, "ccv_cnnp_model.c", 1414, __extension__ __PRETTY_FUNCTION__
); }))
;
1415 int i, j;
1416 for (i = 0; i < tensor_size; i++)
1417 {
1418 ccv_nnc_tensor_symbol_t tensor_symbol = tensor_symbols[i];
1419 if (tensor_symbol.d == CCV_NNC_NO_TENSOR_SYMBOL)
1420 continue;
1421 if (graph)
1422 {
1423 const ccv_nnc_tensor_symbol_t alias_to = ccv_nnc_tensor_symbol_alias_to(graph, tensor_symbol);
1424 if (alias_to.d != CCV_NNC_NO_TENSOR_SYMBOL)
1425 tensor_symbol = alias_to;
1426 }
1427 ccv_nnc_tensor_t* const tensor = CCV_NNC_TENSOR(tensors[i])((ccv_nnc_tensor_t*)((uintptr_t)(tensors[i]) & ~(uintptr_t
)1))
;
1428 if (tensor && tensor_symbol.d != CCV_NNC_NO_TENSOR_SYMBOL)
1429 {
1430 const ccv_nnc_tensor_bind_t retained_bind = {
1431 .symbol = tensor_symbol,
1432 .tensor = tensor
1433 };
1434 ccv_array_push(tensor_binds, &retained_bind);
1435 }
1436 for (j = 1; j < parallel_count; j++)
1437 {
1438 const ccv_nnc_tensor_symbol_t copy = ccv_nnc_tensor_symbol_copy(graph, tensor_symbol, j);
1439 ccv_nnc_tensor_t* copy_tensor = tensors[i + j * tensor_size];
1440 if (copy_tensor && copy.d != CCV_NNC_NO_TENSOR_SYMBOL)
1441 {
1442 const ccv_nnc_tensor_bind_t bind = {
1443 .symbol = copy,
1444 .tensor = tensors[i + j * tensor_size]
1445 };
1446 ccv_array_push(tensor_binds, &bind);
1447 }
1448 }
1449 }
1450}
1451
1452static void _ccv_cnnp_compiled_data_graph_free(ccv_cnnp_compiled_data_t* const compiled_data)
1453{
1454 if (compiled_data->graph)
1455 ccv_nnc_graph_free(compiled_data->graph);
1456 compiled_data->graph = 0;
1457 compiled_data->is_test = 0;
1458 if (compiled_data->tensor_arena)
1459 ccv_nnc_tensor_arena_free(compiled_data->tensor_arena);
1460 compiled_data->tensor_arena = 0;
1461 if (compiled_data->graph_exec_arena)
1462 ccv_nnc_graph_exec_arena_free(compiled_data->graph_exec_arena);
1463 compiled_data->graph_exec_arena = 0;
1464 if (compiled_data->backward.from_ops)
1465 ccfreefree(compiled_data->backward.from_ops);
1466 compiled_data->backward.from_ops = 0;
1467 if (compiled_data->evaluate.schedule)
1468 ccv_nnc_graph_static_schedule_free(compiled_data->evaluate.schedule);
1469 compiled_data->evaluate.schedule = 0;
1470 if (compiled_data->backward.schedule)
1471 ccv_nnc_graph_static_schedule_free(compiled_data->backward.schedule);
1472 compiled_data->backward.schedule = 0;
1473}
1474
1475static void _ccv_cnnp_compiled_data_gradient_free(ccv_cnnp_compiled_data_t* const compiled_data)
1476{
1477 if (compiled_data->gradients)
1478 ccfreefree(compiled_data->gradients);
1479 compiled_data->gradients = 0;
1480 if (compiled_data->updated_parameters)
1481 ccfreefree(compiled_data->updated_parameters);
1482 compiled_data->updated_parameters = 0;
1483 compiled_data->update_nodes = 0;
1484 compiled_data->saved_aux = 0;
1485}
1486
1487static void _ccv_cnnp_compiled_data_backward_free(ccv_cnnp_compiled_data_t* const compiled_data)
1488{
1489 if (compiled_data->backward.gradients)
1490 ccfreefree(compiled_data->backward.gradients);
1491 compiled_data->backward.gradients = 0;
1492 if (compiled_data->backward.accum)
1493 ccv_nnc_graph_free(compiled_data->backward.accum);
1494 compiled_data->backward.accum = 0;
1495 if (compiled_data->backward.tensor_arena)
1496 ccv_nnc_tensor_arena_free(compiled_data->backward.tensor_arena);
1497 compiled_data->backward.tensor_arena = 0;
1498 if (compiled_data->backward.graph_exec_arena)
1499 ccv_nnc_graph_exec_arena_free(compiled_data->backward.graph_exec_arena);
1500 compiled_data->backward.graph_exec_arena = 0;
1501}
1502
1503static void _ccv_cnnp_compiled_data_apply_gradients_free(ccv_cnnp_compiled_data_t* const compiled_data)
1504{
1505 if (compiled_data->apply_gradients.graph)
1506 ccv_nnc_graph_free(compiled_data->apply_gradients.graph);
1507 compiled_data->apply_gradients.graph = 0;
1508 if (compiled_data->apply_gradients.tensor_arena)
1509 ccv_nnc_tensor_arena_free(compiled_data->apply_gradients.tensor_arena);
1510 compiled_data->apply_gradients.tensor_arena = 0;
1511 if (compiled_data->apply_gradients.graph_exec_arena)
1512 ccv_nnc_graph_exec_arena_free(compiled_data->apply_gradients.graph_exec_arena);
1513 compiled_data->apply_gradients.graph_exec_arena = 0;
1514}
1515
1516// Compile the graph to run ccv_cnnp_model_fit
1517static void _ccv_cnnp_model_fit_jit(ccv_cnnp_model_t* const model, ccv_nnc_tensor_t* const* const inputs, const int input_size, ccv_nnc_tensor_t* const* const fits, const int fit_size, ccv_nnc_tensor_t* const* const outputs, const int output_size)
1518{
1519 int i, j;
1520 ccv_cnnp_compiled_data_t* const compiled_data = model->compiled_data;
1521 assert(!compiled_data->graph || compiled_data->graph_mode != CCV_CNNP_MODEL_GRAPH_FIT_MODE)((void) sizeof ((!compiled_data->graph || compiled_data->
graph_mode != CCV_CNNP_MODEL_GRAPH_FIT_MODE) ? 1 : 0), __extension__
({ if (!compiled_data->graph || compiled_data->graph_mode
!= CCV_CNNP_MODEL_GRAPH_FIT_MODE) ; else __assert_fail ("!compiled_data->graph || compiled_data->graph_mode != CCV_CNNP_MODEL_GRAPH_FIT_MODE"
, "ccv_cnnp_model.c", 1521, __extension__ __PRETTY_FUNCTION__
); }))
;
1522 compiled_data->graph_mode = CCV_CNNP_MODEL_GRAPH_FIT_MODE;
1523 const int parallel_count = _ccv_cnnp_model_root_parallel_count(model);
1524 assert(output_size == model->output_size * parallel_count)((void) sizeof ((output_size == model->output_size * parallel_count
) ? 1 : 0), __extension__ ({ if (output_size == model->output_size
* parallel_count) ; else __assert_fail ("output_size == model->output_size * parallel_count"
, "ccv_cnnp_model.c", 1524, __extension__ __PRETTY_FUNCTION__
); }))
;
1525 assert(!fits || output_size == fit_size)((void) sizeof ((!fits || output_size == fit_size) ? 1 : 0), __extension__
({ if (!fits || output_size == fit_size) ; else __assert_fail
("!fits || output_size == fit_size", "ccv_cnnp_model.c", 1525
, __extension__ __PRETTY_FUNCTION__); }))
;
1526 assert(output_size > 0)((void) sizeof ((output_size > 0) ? 1 : 0), __extension__ (
{ if (output_size > 0) ; else __assert_fail ("output_size > 0"
, "ccv_cnnp_model.c", 1526, __extension__ __PRETTY_FUNCTION__
); }))
;
1527 if (compiled_data->gradient_mode == CCV_CNNP_COMPILED_DATA_GRADIENT_NONE)
1528 {
1529 _ccv_cnnp_model_set_rewindables(model);
1530 _ccv_cnnp_model_gradient_init(model, CCV_CNNP_COMPILED_DATA_GRADIENT_TRAINABLES, CCV_CNNP_DISABLE_OUTGRAD_ALL, fits, fit_size);
1531 } else if (compiled_data->gradient_mode != CCV_CNNP_COMPILED_DATA_GRADIENT_TRAINABLES) {
1532 _ccv_cnnp_model_rewind_graph(model);
1533 _ccv_cnnp_compiled_data_gradient_free(compiled_data);
1534 compiled_data->gradient_mode = CCV_CNNP_COMPILED_DATA_GRADIENT_NONE;
1535 _ccv_cnnp_model_gradient_init(model, CCV_CNNP_COMPILED_DATA_GRADIENT_TRAINABLES, CCV_CNNP_DISABLE_OUTGRAD_ALL, fits, fit_size);
1536 }
1537 const int tensors_init = !!compiled_data->tensors_init.v;
1538 if (!tensors_init)
1539 _ccv_cnnp_model_tensors_init(model, compiled_data);
1540 else if ((uintptr_t)compiled_data->tensors_init.v & (uintptr_t)1)
1541 // Check if it is not fully allocated, if it is not, init_1.
1542 ccv_cnnp_model_tensors_init_1(model, compiled_data);
1543 ccv_array_t* const tensor_binds = ccv_array_new(sizeof(ccv_nnc_tensor_bind_t), 0, 0);
1544 assert((input_size % parallel_count) == 0)((void) sizeof (((input_size % parallel_count) == 0) ? 1 : 0)
, __extension__ ({ if ((input_size % parallel_count) == 0) ; else
__assert_fail ("(input_size % parallel_count) == 0", "ccv_cnnp_model.c"
, 1544, __extension__ __PRETTY_FUNCTION__); }))
;
1545 assert((output_size % parallel_count) == 0)((void) sizeof (((output_size % parallel_count) == 0) ? 1 : 0
), __extension__ ({ if ((output_size % parallel_count) == 0) ;
else __assert_fail ("(output_size % parallel_count) == 0", "ccv_cnnp_model.c"
, 1545, __extension__ __PRETTY_FUNCTION__); }))
;
1546 assert((fit_size % parallel_count) == 0)((void) sizeof (((fit_size % parallel_count) == 0) ? 1 : 0), __extension__
({ if ((fit_size % parallel_count) == 0) ; else __assert_fail
("(fit_size % parallel_count) == 0", "ccv_cnnp_model.c", 1546
, __extension__ __PRETTY_FUNCTION__); }))
;
1547 const int input_size_per_p = input_size / parallel_count;
1548 _ccv_cnnp_model_bind_tensors(model->graph, model->inputs, inputs, input_size_per_p, parallel_count, tensor_binds);
1549 const int output_size_per_p = output_size / parallel_count;
1550 _ccv_cnnp_model_bind_tensors(model->graph, model->outputs, outputs, output_size_per_p, parallel_count, tensor_binds);
1551 const int fit_size_per_p = fit_size / parallel_count;
1552 _ccv_cnnp_model_bind_tensors(model->graph, compiled_data->fits, fits, fit_size_per_p, parallel_count, tensor_binds);
1553 const int parameter_size = compiled_data->parameters->rnum;
1554 _ccv_cnnp_model_bind_tensors(model->graph, (ccv_nnc_tensor_symbol_t*)ccv_array_get(compiled_data->parameters, 0)((void*)(((char*)((compiled_data->parameters)->data)) +
(size_t)(compiled_data->parameters)->rsize * (size_t)(
0)))
, compiled_data->tensors.parameters, parameter_size, parallel_count, tensor_binds);
1555 _ccv_cnnp_model_bind_tensors(model->graph, compiled_data->updated_parameters, compiled_data->tensors.parameters, parameter_size, parallel_count, tensor_binds);
1556 const int internal_size = compiled_data->internals->rnum;
1557 _ccv_cnnp_model_remove_nocopies(model->graph, (ccv_nnc_tensor_symbol_t*)ccv_array_get(compiled_data->internals, 0)((void*)(((char*)((compiled_data->internals)->data)) + (
size_t)(compiled_data->internals)->rsize * (size_t)(0))
)
, compiled_data->tensors.internals, internal_size, parallel_count);
1558 _ccv_cnnp_model_bind_tensors(model->graph, (ccv_nnc_tensor_symbol_t*)ccv_array_get(compiled_data->internals, 0)((void*)(((char*)((compiled_data->internals)->data)) + (
size_t)(compiled_data->internals)->rsize * (size_t)(0))
)
, compiled_data->tensors.internals, internal_size, parallel_count, tensor_binds);
1559 ccv_nnc_symbolic_graph_compile(model->graph, compiled_data->compile_params, (ccv_nnc_tensor_bind_t*)ccv_array_get(tensor_binds, 0)((void*)(((char*)((tensor_binds)->data)) + (size_t)(tensor_binds
)->rsize * (size_t)(0)))
, tensor_binds->rnum, 0, 0, SYMBOLIC_GRAPH_SOURCES(model->graph)ccv_nnc_symbolic_graph_sources(model->graph), ccv_nnc_symbolic_graph_source_size
(model->graph)
, SYMBOLIC_GRAPH_DESTINATIONS(model->graph)ccv_nnc_symbolic_graph_destinations(model->graph), ccv_nnc_symbolic_graph_destination_size
(model->graph)
, &compiled_data->graph, &compiled_data->tensor_arena, &compiled_data->graph_exec_arena);
1560 ccv_array_free(tensor_binds);
1561 const uint32_t* const init_v = CCV_NNC_INIT_V(compiled_data->tensors_init.v)((uint32_t*)((uintptr_t)(compiled_data->tensors_init.v) &
~(uintptr_t)1))
;
1562 if (tensors_init && parallel_count > 1)
1563 _ccv_cnnp_model_copy_tensors(init_v, (ccv_nnc_tensor_symbol_t*)ccv_array_get(compiled_data->parameters, 0)((void*)(((char*)((compiled_data->parameters)->data)) +
(size_t)(compiled_data->parameters)->rsize * (size_t)(
0)))
, compiled_data->tensors.parameters, compiled_data->parameters->rnum, parallel_count);
1564 // If tensor is not init'ed, we need to init states first.
1565 if (_ccv_cnnp_any_to_init(compiled_data))
1566 {
1567 ccv_nnc_tensor_init_states_t tensor_init_states = {
1568 .parallel_count = parallel_count,
1569 .graph = model->graph,
1570 .compiled_data = compiled_data,
1571 .tensor_arena = compiled_data->tensor_arena
1572 };
1573 ccv_cnnp_model_init_states(model, model->graph, _ccv_cnnp_init_states_for_tensors, &tensor_init_states);
1574 }
1575 compiled_data->is_test = 0;
1576 const int saved_aux_size = ccv_nnc_minimizer_saved_aux_size(compiled_data->minimize.minimizer);
1577 // No need to set because it is default to training mode.
1578 // ccv_cnnp_model_set_is_test(model, 0, _ccv_cnnp_cmd_update_for_execs, &update);
1579 for (i = 0; i < saved_aux_size * parameter_size; i++)
1580 {
1581 if (compiled_data->saved_aux[i].source.d == CCV_NNC_NO_TENSOR_SYMBOL)
1582 continue;
1583 ccv_nnc_tensor_t* const tensor = ccv_nnc_tensor_from_symbol(compiled_data->tensor_arena, compiled_data->saved_aux[i].source);
1584 ccv_nnc_cmd_exec(CMD_SET_FORWARD(0)ccv_nnc_cmd(CCV_NNC_SET_FORWARD, 0, (ccv_nnc_cmd_param_t){.size
={.dim={1,1,1}},.blas={.a={0,}}}, 0)
, ccv_nnc_no_hint, 0, 0, 0, &tensor, 1, 0);
1585 for (j = 1; j < parallel_count; j++)
1586 {
1587 ccv_nnc_tensor_t* const copy = ccv_nnc_tensor_from_symbol(compiled_data->tensor_arena, ccv_nnc_tensor_symbol_copy(model->graph, compiled_data->saved_aux[i].source, j));
1588 if (copy)
1589 ccv_nnc_cmd_exec(CMD_SET_FORWARD(0)ccv_nnc_cmd(CCV_NNC_SET_FORWARD, 0, (ccv_nnc_cmd_param_t){.size
={.dim={1,1,1}},.blas={.a={0,}}}, 0)
, ccv_nnc_no_hint, 0, 0, 0, &copy, 1, 0);
1590 }
1591 }
1592 const int evaluate_to_size = compiled_data->evaluate.to_size;
1593 compiled_data->evaluate.to_op_size = 0;
1594 for (i = 0; i < evaluate_to_size; i++)
1595 {
1596 ccv_nnc_graph_exec_t const to = ccv_nnc_graph_exec_from_symbol(compiled_data->graph_exec_arena, compiled_data->evaluate.tos[i]);
1597 if (to.graph)
1598 compiled_data->evaluate.to_ops[compiled_data->evaluate.to_op_size++] = to;
1599 }
1600 ccv_nnc_graph_set_default_static_schedule(compiled_data->graph, compiled_data->stream_type, model->max_stream_count);
1601 ccv_nnc_graph_autotune(compiled_data->graph, model->workspace_size, 0, TRAVERSE_FULL0,0,0,0);
1602}
1603
1604ccv_nnc_stream_context_t* ccv_cnnp_model_default_stream(const ccv_cnnp_model_t* const model)
1605{
1606 const ccv_cnnp_compiled_data_t* const compiled_data = model->compiled_data;
1607 if (!compiled_data || !compiled_data->graph)
1608 return 0;
1609 return ccv_nnc_graph_default_stream(compiled_data->graph);
1610}
1611
1612uint64_t ccv_cnnp_model_memory_size(const ccv_cnnp_model_t* const model)
1613{
1614 const ccv_cnnp_compiled_data_t* const compiled_data = model->compiled_data;
1615 if (!compiled_data || !compiled_data->tensor_arena)
1616 return 0;
1617 return ccv_nnc_tensor_arena_size(compiled_data->tensor_arena);
1618}
1619
1620static void _ccv_cnnp_bind_tensors_to_arena(ccv_nnc_tensor_arena_t* const tensor_arena, const ccv_nnc_symbolic_graph_t* const graph, const ccv_nnc_tensor_symbol_t* const tensor_symbols, ccv_nnc_tensor_t* const* const tensors, const int tensor_size, const int parallel_count)
1621{
1622 int i, j;
1623 for (i = 0; i < tensor_size; i++)
1624 {
1625 ccv_nnc_tensor_symbol_t tensor_symbol = tensor_symbols[i];
1626 if (tensor_symbol.d == CCV_NNC_NO_TENSOR_SYMBOL)
1627 continue;
1628 if (graph)
1629 {
1630 const ccv_nnc_tensor_symbol_t alias_to = ccv_nnc_tensor_symbol_alias_to(graph, tensor_symbol);
1631 if (alias_to.d != CCV_NNC_NO_TENSOR_SYMBOL)
1632 tensor_symbol = alias_to;
1633 }
1634 ccv_nnc_tensor_bind_symbol(tensor_arena, tensor_symbol, tensors[i]);
1635 for (j = 1; j < parallel_count; j++)
1636 {
1637 const ccv_nnc_tensor_symbol_t copy = ccv_nnc_tensor_symbol_copy(graph, tensor_symbol, j);
1638 if (copy.d != CCV_NNC_NO_TENSOR_SYMBOL)
1639 ccv_nnc_tensor_bind_symbol(tensor_arena, copy, tensors[i + tensor_size * j]);
1640 }
1641 }
1642}
1643
1644void ccv_cnnp_model_fit(ccv_cnnp_model_t* const model, ccv_nnc_tensor_t* const* const inputs, const int input_size, ccv_nnc_tensor_t* const* const fits, const int fit_size, ccv_nnc_tensor_t* const* const outputs, const int output_size, ccv_nnc_tensor_tape_t* const tensor_tape, ccv_nnc_stream_context_t* const stream_context)
1645{
1646 ccv_cnnp_compiled_data_t* const compiled_data = model->compiled_data;
1647 assert(compiled_data)((void) sizeof ((compiled_data) ? 1 : 0), __extension__ ({ if
(compiled_data) ; else __assert_fail ("compiled_data", "ccv_cnnp_model.c"
, 1647, __extension__ __PRETTY_FUNCTION__); }))
;
1648 const int parallel_count = ccv_max(model->parallel_count, 1)({ typeof (model->parallel_count) _a = (model->parallel_count
); typeof (1) _b = (1); (_a > _b) ? _a : _b; })
;
1649 assert(output_size == model->output_size * parallel_count)((void) sizeof ((output_size == model->output_size * parallel_count
) ? 1 : 0), __extension__ ({ if (output_size == model->output_size
* parallel_count) ; else __assert_fail ("output_size == model->output_size * parallel_count"
, "ccv_cnnp_model.c", 1649, __extension__ __PRETTY_FUNCTION__
); }))
;
1650 assert(input_size == model->input_size * parallel_count)((void) sizeof ((input_size == model->input_size * parallel_count
) ? 1 : 0), __extension__ ({ if (input_size == model->input_size
* parallel_count) ; else __assert_fail ("input_size == model->input_size * parallel_count"
, "ccv_cnnp_model.c", 1650, __extension__ __PRETTY_FUNCTION__
); }))
;
1651 assert(!fits || fit_size == output_size)((void) sizeof ((!fits || fit_size == output_size) ? 1 : 0), __extension__
({ if (!fits || fit_size == output_size) ; else __assert_fail
("!fits || fit_size == output_size", "ccv_cnnp_model.c", 1651
, __extension__ __PRETTY_FUNCTION__); }))
;
1652 assert(model->graph)((void) sizeof ((model->graph) ? 1 : 0), __extension__ ({ if
(model->graph) ; else __assert_fail ("model->graph", "ccv_cnnp_model.c"
, 1652, __extension__ __PRETTY_FUNCTION__); }))
;
1653 if (!compiled_data->graph || compiled_data->graph_mode != CCV_CNNP_MODEL_GRAPH_FIT_MODE)
1654 {
1655 _ccv_cnnp_compiled_data_graph_free(compiled_data);
1656 _ccv_cnnp_compiled_data_backward_free(compiled_data);
1657 _ccv_cnnp_compiled_data_apply_gradients_free(compiled_data);
1658 // Compile the symbolic graph down only when needed.
1659 _ccv_cnnp_model_fit_jit(model, inputs, input_size, fits, fit_size, outputs, output_size);
1660 } else {
1661 assert((input_size % parallel_count) == 0)((void) sizeof (((input_size % parallel_count) == 0) ? 1 : 0)
, __extension__ ({ if ((input_size % parallel_count) == 0) ; else
__assert_fail ("(input_size % parallel_count) == 0", "ccv_cnnp_model.c"
, 1661, __extension__ __PRETTY_FUNCTION__); }))
;
1662 assert((output_size % parallel_count) == 0)((void) sizeof (((output_size % parallel_count) == 0) ? 1 : 0
), __extension__ ({ if ((output_size % parallel_count) == 0) ;
else __assert_fail ("(output_size % parallel_count) == 0", "ccv_cnnp_model.c"
, 1662, __extension__ __PRETTY_FUNCTION__); }))
;
1663 assert((fit_size % parallel_count) == 0)((void) sizeof (((fit_size % parallel_count) == 0) ? 1 : 0), __extension__
({ if ((fit_size % parallel_count) == 0) ; else __assert_fail
("(fit_size % parallel_count) == 0", "ccv_cnnp_model.c", 1663
, __extension__ __PRETTY_FUNCTION__); }))
;
1664 const int input_size_per_p = input_size / parallel_count;
1665 _ccv_cnnp_bind_tensors_to_arena(compiled_data->tensor_arena, model->graph, model->inputs, inputs, input_size_per_p, parallel_count);
1666 const int output_size_per_p = output_size / parallel_count;
1667 _ccv_cnnp_bind_tensors_to_arena(compiled_data->tensor_arena, model->graph, model->outputs, outputs, output_size_per_p, parallel_count);
1668 const int fit_size_per_p = fit_size / parallel_count;
1669 _ccv_cnnp_bind_tensors_to_arena(compiled_data->tensor_arena, model->graph, compiled_data->fits, fits, fit_size_per_p, parallel_count);
1670 }
1671 if (compiled_data->is_test)
1672 {
1673 compiled_data->is_test = 0;
1674 ccv_nnc_graph_exec_update_t update = {
1675 .parallel_count = parallel_count,
1676 .graph = model->graph,
1677 .graph_exec_arena = compiled_data->graph_exec_arena,
1678 };
1679 ccv_cnnp_model_set_is_test(model, 0, _ccv_cnnp_cmd_update_for_execs, &update);
1680 }
1681 ccv_nnc_graph_run_with_schedule(compiled_data->graph, 0, 0, tensor_tape, stream_context);
1682}
1683
1684// Compile the graph to run ccv_cnnp_model_evaluate with require_grad = false (MULTISTAGE_MODE_NO_GRAD).
1685static void _ccv_cnnp_model_multistage_no_grad_jit(ccv_cnnp_model_t* const model, ccv_nnc_tensor_t* const* const inputs, const int input_size, ccv_nnc_tensor_t* const* const outputs, const int output_size)
1686{
1687 ccv_cnnp_compiled_data_t* const compiled_data = model->compiled_data;
1688 compiled_data->graph_mode = CCV_CNNP_MODEL_GRAPH_MULTISTAGE_MODE_NO_GRAD;
1689 const int parallel_count = ccv_max(model->parallel_count, 1)({ typeof (model->parallel_count) _a = (model->parallel_count
); typeof (1) _b = (1); (_a > _b) ? _a : _b; })
;
1690 assert(output_size == model->output_size * parallel_count)((void) sizeof ((output_size == model->output_size * parallel_count
) ? 1 : 0), __extension__ ({ if (output_size == model->output_size
* parallel_count) ; else __assert_fail ("output_size == model->output_size * parallel_count"
, "ccv_cnnp_model.c", 1690, __extension__ __PRETTY_FUNCTION__
); }))
;
1691 assert(output_size > 0)((void) sizeof ((output_size > 0) ? 1 : 0), __extension__ (
{ if (output_size > 0) ; else __assert_fail ("output_size > 0"
, "ccv_cnnp_model.c", 1691, __extension__ __PRETTY_FUNCTION__
); }))
;
1692 // If the gradient is not initialized, continue to setup parallel process. We don't init gradient here, but rather,
1693 // we setup proper rewindables so the graph can be rewinded to previous state before we run data parallel.
1694 if (parallel_count > 1 && compiled_data->gradient_mode == CCV_CNNP_COMPILED_DATA_GRADIENT_NONE)
1695 {
1696 const int evaluate_to_size = compiled_data->evaluate.to_size;
1697 compiled_data->evaluate.tos = ccreallocrealloc(compiled_data->evaluate.tos, sizeof(ccv_nnc_graph_exec_symbol_t) * evaluate_to_size * parallel_count + sizeof(ccv_nnc_graph_exec_t) * evaluate_to_size * parallel_count);
1698 _ccv_cnnp_model_set_rewindables(model);
1699 ccv_nnc_symbolic_graph_data_parallel(model->graph, parallel_count,
1700 0, 0,
1701 0, 0, 0,
1702 0, 0, 0,
1703 CCV_NNC_PARALLEL_REDUCE_OP_SUM,
1704 SYMBOLIC_GRAPH_SOURCES(model->graph)ccv_nnc_symbolic_graph_sources(model->graph), ccv_nnc_symbolic_graph_source_size
(model->graph)
, SYMBOLIC_GRAPH_DESTINATIONS(model->graph)ccv_nnc_symbolic_graph_destinations(model->graph), ccv_nnc_symbolic_graph_destination_size
(model->graph)
);
1705 ccv_nnc_graph_exec_symbol_autogen(model->graph, 0, 0, CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
1706 int i, j;
1707 for (i = 0; i < evaluate_to_size; i++)
1708 for (j = 1; j < parallel_count; j++)
1709 {
1710 const ccv_nnc_graph_exec_symbol_t copy = ccv_nnc_graph_exec_symbol_copy(model->graph, compiled_data->evaluate.tos[i], j);
1711 if (copy.d != CCV_NNC_NO_GRAPH_EXEC_SYMBOL)
1712 compiled_data->evaluate.tos[compiled_data->evaluate.to_size++] = copy;
1713 }
1714 }
1715 const int tensors_init = !!compiled_data->tensors_init.v;
1716 if (!tensors_init)
1717 _ccv_cnnp_model_tensors_init(model, compiled_data);
1718 else if ((uintptr_t)compiled_data->tensors_init.v & (uintptr_t)1)
1719 // Check if it is not fully allocated, if it is not, init_1.
1720 ccv_cnnp_model_tensors_init_1(model, compiled_data);
1721 const int tensor_parallel_count = _ccv_cnnp_compiled_data_parallel_count(model, compiled_data);
1722 ccv_array_t* const tensor_binds = ccv_array_new(sizeof(ccv_nnc_tensor_bind_t), 0, 0);
1723 assert((input_size % parallel_count) == 0)((void) sizeof (((input_size % parallel_count) == 0) ? 1 : 0)
, __extension__ ({ if ((input_size % parallel_count) == 0) ; else
__assert_fail ("(input_size % parallel_count) == 0", "ccv_cnnp_model.c"
, 1723, __extension__ __PRETTY_FUNCTION__); }))
;
1724 assert((output_size % parallel_count) == 0)((void) sizeof (((output_size % parallel_count) == 0) ? 1 : 0
), __extension__ ({ if ((output_size % parallel_count) == 0) ;
else __assert_fail ("(output_size % parallel_count) == 0", "ccv_cnnp_model.c"
, 1724, __extension__ __PRETTY_FUNCTION__); }))
;
1725 const int input_size_per_p = input_size / parallel_count;
1726 _ccv_cnnp_model_bind_tensors(model->graph, model->inputs, inputs, input_size_per_p, parallel_count, tensor_binds);
1727 const int output_size_per_p = output_size / parallel_count;
1728 _ccv_cnnp_model_bind_tensors(model->graph, model->outputs, outputs, output_size_per_p, parallel_count, tensor_binds);
1729 const int parameter_size = compiled_data->parameters->rnum;
1730 _ccv_cnnp_model_bind_tensors(model->graph, (ccv_nnc_tensor_symbol_t*)ccv_array_get(compiled_data->parameters, 0)((void*)(((char*)((compiled_data->parameters)->data)) +
(size_t)(compiled_data->parameters)->rsize * (size_t)(
0)))
, compiled_data->tensors.parameters, parameter_size, tensor_parallel_count, tensor_binds);
1731 const int internal_size = compiled_data->internals->rnum;
1732 _ccv_cnnp_model_remove_nocopies(model->graph, (ccv_nnc_tensor_symbol_t*)ccv_array_get(compiled_data->internals, 0)((void*)(((char*)((compiled_data->internals)->data)) + (
size_t)(compiled_data->internals)->rsize * (size_t)(0))
)
, compiled_data->tensors.internals, internal_size, tensor_parallel_count);
1733 _ccv_cnnp_model_bind_tensors(model->graph, (ccv_nnc_tensor_symbol_t*)ccv_array_get(compiled_data->internals, 0)((void*)(((char*)((compiled_data->internals)->data)) + (
size_t)(compiled_data->internals)->rsize * (size_t)(0))
)
, compiled_data->tensors.internals, internal_size, tensor_parallel_count, tensor_binds);
1734 // If we generated gradient for the graph, only compile part of the graph because the rest is irrelevant for evaluation.
1735 ccv_nnc_symbolic_graph_compile(model->graph, compiled_data->compile_params, (ccv_nnc_tensor_bind_t*)ccv_array_get(tensor_binds, 0)((void*)(((char*)((tensor_binds)->data)) + (size_t)(tensor_binds
)->rsize * (size_t)(0)))
, tensor_binds->rnum, 0, 0, SYMBOLIC_GRAPH_SOURCES(model->graph)ccv_nnc_symbolic_graph_sources(model->graph), ccv_nnc_symbolic_graph_source_size
(model->graph)
, compiled_data->evaluate.tos, compiled_data->evaluate.to_size, &compiled_data->graph, &compiled_data->tensor_arena, &compiled_data->graph_exec_arena);
1736 ccv_array_free(tensor_binds);
1737 const uint32_t* const init_v = CCV_NNC_INIT_V(compiled_data->tensors_init.v)((uint32_t*)((uintptr_t)(compiled_data->tensors_init.v) &
~(uintptr_t)1))
;
1738 // If tensor is not init'ed, we need to init states first.
1739 if (tensors_init && tensor_parallel_count > 1)
1740 _ccv_cnnp_model_copy_tensors(init_v, (ccv_nnc_tensor_symbol_t*)ccv_array_get(compiled_data->parameters, 0)((void*)(((char*)((compiled_data->parameters)->data)) +
(size_t)(compiled_data->parameters)->rsize * (size_t)(
0)))
, compiled_data->tensors.parameters, compiled_data->parameters->rnum, tensor_parallel_count);
1741 if (_ccv_cnnp_any_to_init(compiled_data))
1742 {
1743 ccv_nnc_tensor_init_states_t tensor_init_states = {
1744 .parallel_count = tensor_parallel_count,
1745 .graph = model->graph,
1746 .compiled_data = compiled_data,
1747 .tensor_arena = compiled_data->tensor_arena
1748 };
1749 ccv_cnnp_model_init_states(model, model->graph, _ccv_cnnp_init_states_for_tensors, &tensor_init_states);
1750 }
1751 compiled_data->is_test = 1;
1752 ccv_nnc_graph_exec_update_t update = {
1753 .parallel_count = parallel_count,
1754 .graph = model->graph,
1755 .graph_exec_arena = compiled_data->graph_exec_arena,
1756 };
1757 ccv_cnnp_model_set_is_test(model, 1, _ccv_cnnp_cmd_update_for_execs, &update);
1758 ccv_nnc_graph_set_default_static_schedule(compiled_data->graph, compiled_data->stream_type, model->max_stream_count);
1759 ccv_nnc_graph_autotune(compiled_data->graph, model->workspace_size, 0, TRAVERSE_FULL0,0,0,0);
1760}
1761
1762static void _ccv_cnnp_model_gradient_tensors_init(const ccv_cnnp_model_t* const model, ccv_cnnp_compiled_data_t* const compiled_data)
1763{
1764 assert(!compiled_data->tensors.gradients)((void) sizeof ((!compiled_data->tensors.gradients) ? 1 : 0
), __extension__ ({ if (!compiled_data->tensors.gradients)
; else __assert_fail ("!compiled_data->tensors.gradients"
, "ccv_cnnp_model.c", 1764, __extension__ __PRETTY_FUNCTION__
); }))
;
1765 const int parameter_size = compiled_data->parameters->rnum;
1766 const int parallel_count = ccv_max(model->parallel_count, 1)({ typeof (model->parallel_count) _a = (model->parallel_count
); typeof (1) _b = (1); (_a > _b) ? _a : _b; })
;
1767 compiled_data->tensors.gradients = (ccv_nnc_tensor_t**)ccmallocmalloc(sizeof(ccv_nnc_tensor_t*) * parameter_size * 2 * parallel_count);
1768 compiled_data->tensors.accum_gradients = compiled_data->tensors.gradients + parameter_size * parallel_count;
1769 int i, j;
1770 for (i = 0; i < parameter_size; i++)
1771 {
1772 if (compiled_data->parameter_flags && !(compiled_data->parameter_flags[i >> 6] & ((uint64_t)1 << (i & 63))))
1773 {
1774 compiled_data->tensors.gradients[i] = 0;
1775 compiled_data->tensors.accum_gradients[i] = 0;
1776 for (j = 1; j < parallel_count; j++)
1777 {
1778 compiled_data->tensors.gradients[i + j * parameter_size] = 0;
1779 compiled_data->tensors.accum_gradients[i + j * parameter_size] = 0;
1780 }
1781 continue;
1782 }
1783 const ccv_nnc_tensor_symbol_t parameter = *(ccv_nnc_tensor_symbol_t*)ccv_array_get(compiled_data->parameters, i)((void*)(((char*)((compiled_data->parameters)->data)) +
(size_t)(compiled_data->parameters)->rsize * (size_t)(
i)))
;
1784 ccv_nnc_tensor_param_t info = ccv_nnc_tensor_symbol_params(parameter.graph, parameter);
1785 if (CCV_TENSOR_GET_DEVICE(info.type)((info.type) & 0xfff00) == CCV_COMPUTE_DEVICE_ANY)
1786 CCV_TENSOR_SET_DEVICE_ID(info.type, 0)(info.type) = (((info.type) & ~0xfff00) | (((0) & 0xfff
) << 8))
;
1787 const int device_id = CCV_TENSOR_GET_DEVICE_ID(info.type)(((info.type) & 0xfff00) >> 8);
1788 compiled_data->tensors.gradients[i] = ccv_nnc_tensor_new(0, info, 0);
1789 compiled_data->tensors.accum_gradients[i] = 0; // delay the accumulated gradient allocation until when we need it.
1790 for (j = 1; j < parallel_count; j++)
1791 {
1792 if (j != device_id)
1793 CCV_TENSOR_SET_DEVICE_ID(info.type, j)(info.type) = (((info.type) & ~0xfff00) | (((j) & 0xfff
) << 8))
;
1794 else
1795 CCV_TENSOR_SET_DEVICE_ID(info.type, 0)(info.type) = (((info.type) & ~0xfff00) | (((0) & 0xfff
) << 8))
;
1796 compiled_data->tensors.gradients[i + j * parameter_size] = ccv_nnc_tensor_new(0, info, 0);
1797 compiled_data->tensors.accum_gradients[i + j * parameter_size] = 0;
1798 }
1799 }
1800}
1801
1802static int _ccv_cnnp_is_disable_outgrad_all(const uint64_t disable_outgrad, const int input_size)
1803{
1804 if (disable_outgrad == CCV_CNNP_DISABLE_OUTGRAD_ALL)
1805 return 1;
1806 if (disable_outgrad == CCV_CNNP_DISABLE_OUTGRAD_NONE)
1807 return 0;
1808 int i;
1809 for (i = 0; i < input_size; i++)
1810 if (!(disable_outgrad & ((uint64_t)1 << i)))
1811 return 0;
1812 return 1;
1813}
1814
1815// Compile the graph to run ccv_cnnp_model_evaluate with requires_grad = true (MULTISTAGE_MODE).
1816// Particularly, this method compiles the evaluation and backprop graph (the main graph).
1817static void _ccv_cnnp_model_multistage_jit_0(ccv_cnnp_model_t* const model, const uint64_t disable_outgrad, const int is_test, ccv_nnc_tensor_t* const* const inputs, const int input_size, ccv_nnc_tensor_t* const* const outputs, const int output_size)
1818{
1819 int i, j;
1820 ccv_cnnp_compiled_data_t* const compiled_data = model->compiled_data;
1821 const int target_gradient_mode = _ccv_cnnp_is_disable_outgrad_all(disable_outgrad, model->input_size) ? CCV_CNNP_COMPILED_DATA_GRADIENT_TRAINABLES : CCV_CNNP_COMPILED_DATA_GRADIENT_TRAINABLES_AND_INPUTS;
1822 assert(!compiled_data->graph || compiled_data->graph_mode != CCV_CNNP_MODEL_GRAPH_MULTISTAGE_MODE || compiled_data->gradient_mode != target_gradient_mode)((void) sizeof ((!compiled_data->graph || compiled_data->
graph_mode != CCV_CNNP_MODEL_GRAPH_MULTISTAGE_MODE || compiled_data
->gradient_mode != target_gradient_mode) ? 1 : 0), __extension__
({ if (!compiled_data->graph || compiled_data->graph_mode
!= CCV_CNNP_MODEL_GRAPH_MULTISTAGE_MODE || compiled_data->
gradient_mode != target_gradient_mode) ; else __assert_fail (
"!compiled_data->graph || compiled_data->graph_mode != CCV_CNNP_MODEL_GRAPH_MULTISTAGE_MODE || compiled_data->gradient_mode != target_gradient_mode"
, "ccv_cnnp_model.c", 1822, __extension__ __PRETTY_FUNCTION__
); }))
;
1823 compiled_data->graph_mode = CCV_CNNP_MODEL_GRAPH_MULTISTAGE_MODE;
1824 const int parallel_count = ccv_max(model->parallel_count, 1)({ typeof (model->parallel_count) _a = (model->parallel_count
); typeof (1) _b = (1); (_a > _b) ? _a : _b; })
;
1825 assert(output_size == model->output_size * parallel_count)((void) sizeof ((output_size == model->output_size * parallel_count
) ? 1 : 0), __extension__ ({ if (output_size == model->output_size
* parallel_count) ; else __assert_fail ("output_size == model->output_size * parallel_count"
, "ccv_cnnp_model.c", 1825, __extension__ __PRETTY_FUNCTION__
); }))
;
1826 assert(output_size > 0)((void) sizeof ((output_size > 0) ? 1 : 0), __extension__ (
{ if (output_size > 0) ; else __assert_fail ("output_size > 0"
, "ccv_cnnp_model.c", 1826, __extension__ __PRETTY_FUNCTION__
); }))
;
1827 // There shouldn't be a loss function if we evaluate with multistage jit.
1828 assert(compiled_data->loss.cmd == CCV_NNC_NOOP)((void) sizeof ((compiled_data->loss.cmd == CCV_NNC_NOOP) ?
1 : 0), __extension__ ({ if (compiled_data->loss.cmd == CCV_NNC_NOOP
) ; else __assert_fail ("compiled_data->loss.cmd == CCV_NNC_NOOP"
, "ccv_cnnp_model.c", 1828, __extension__ __PRETTY_FUNCTION__
); }))
;
1829 if (compiled_data->gradient_mode == CCV_CNNP_COMPILED_DATA_GRADIENT_NONE)
1830 {
1831 _ccv_cnnp_model_set_rewindables(model);
1832 _ccv_cnnp_model_gradient_init(model, target_gradient_mode, disable_outgrad, 0, 0); // The type of outputs and fits should be the same. We only use type here.
1833 } else if (compiled_data->gradient_mode != target_gradient_mode) {
1834 _ccv_cnnp_model_rewind_graph(model);
1835 _ccv_cnnp_compiled_data_gradient_free(compiled_data);
1836 compiled_data->gradient_mode = CCV_CNNP_COMPILED_DATA_GRADIENT_NONE;
1837 _ccv_cnnp_model_gradient_init(model, target_gradient_mode, disable_outgrad, 0, 0); // The type of outputs and fits should be the same. We only use type here.
1838 }
1839 const int tensors_init = !!compiled_data->tensors_init.v;
1840 if (!tensors_init)
1841 _ccv_cnnp_model_tensors_init(model, compiled_data);
1842 else if ((uintptr_t)compiled_data->tensors_init.v & (uintptr_t)1)
1843 // Check if it is not fully allocated, if it is not, init_1.
1844 ccv_cnnp_model_tensors_init_1(model, compiled_data);
1845 ccv_array_t* const tensor_binds = ccv_array_new(sizeof(ccv_nnc_tensor_bind_t), 0, 0);
1846 assert((input_size % parallel_count) == 0)((void) sizeof (((input_size % parallel_count) == 0) ? 1 : 0)
, __extension__ ({ if ((input_size % parallel_count) == 0) ; else
__assert_fail ("(input_size % parallel_count) == 0", "ccv_cnnp_model.c"
, 1846, __extension__ __PRETTY_FUNCTION__); }))
;
1847 assert((output_size % parallel_count) == 0)((void) sizeof (((output_size % parallel_count) == 0) ? 1 : 0
), __extension__ ({ if ((output_size % parallel_count) == 0) ;
else __assert_fail ("(output_size % parallel_count) == 0", "ccv_cnnp_model.c"
, 1847, __extension__ __PRETTY_FUNCTION__); }))
;
1848 const int input_size_per_p = input_size / parallel_count;
1849 _ccv_cnnp_model_bind_tensors(model->graph, model->inputs, inputs, input_size_per_p, parallel_count, tensor_binds);
1850 const int output_size_per_p = output_size / parallel_count;
1851 _ccv_cnnp_model_bind_tensors(model->graph, model->outputs, outputs, output_size_per_p, parallel_count, tensor_binds);
1852 const int parameter_size = compiled_data->parameters->rnum;
1853 _ccv_cnnp_model_bind_tensors(model->graph, (ccv_nnc_tensor_symbol_t*)ccv_array_get(compiled_data->parameters, 0)((void*)(((char*)((compiled_data->parameters)->data)) +
(size_t)(compiled_data->parameters)->rsize * (size_t)(
0)))
, compiled_data->tensors.parameters, parameter_size, parallel_count, tensor_binds);
1854 const int internal_size = compiled_data->internals->rnum;
1855 _ccv_cnnp_model_remove_nocopies(model->graph, (ccv_nnc_tensor_symbol_t*)ccv_array_get(compiled_data->internals, 0)((void*)(((char*)((compiled_data->internals)->data)) + (
size_t)(compiled_data->internals)->rsize * (size_t)(0))
)
, compiled_data->tensors.internals, internal_size, parallel_count);
1856 _ccv_cnnp_model_bind_tensors(model->graph, (ccv_nnc_tensor_symbol_t*)ccv_array_get(compiled_data->internals, 0)((void*)(((char*)((compiled_data->internals)->data)) + (
size_t)(compiled_data->internals)->rsize * (size_t)(0))
)
, compiled_data->tensors.internals, internal_size, parallel_count, tensor_binds);
1857 if (!compiled_data->tensors.gradients)
1858 _ccv_cnnp_model_gradient_tensors_init(model, compiled_data);
1859 _ccv_cnnp_model_bind_tensors(model->graph, compiled_data->gradients, compiled_data->tensors.gradients, parameter_size, parallel_count, tensor_binds);
1860 if (compiled_data->backward.to_size > 0)
1861 ccv_nnc_symbolic_graph_compile(model->graph, compiled_data->compile_params, (ccv_nnc_tensor_bind_t*)ccv_array_get(tensor_binds, 0)((void*)(((char*)((tensor_binds)->data)) + (size_t)(tensor_binds
)->rsize * (size_t)(0)))
, tensor_binds->rnum, 0, 0, SYMBOLIC_GRAPH_SOURCES(model->graph)ccv_nnc_symbolic_graph_sources(model->graph), ccv_nnc_symbolic_graph_source_size
(model->graph)
, compiled_data->backward.tos, compiled_data->backward.to_size, &compiled_data->graph, &compiled_data->tensor_arena, &compiled_data->graph_exec_arena);
1862 else
1863 ccv_nnc_symbolic_graph_compile(model->graph, compiled_data->compile_params, (ccv_nnc_tensor_bind_t*)ccv_array_get(tensor_binds, 0)((void*)(((char*)((tensor_binds)->data)) + (size_t)(tensor_binds
)->rsize * (size_t)(0)))
, tensor_binds->rnum, 0, 0, SYMBOLIC_GRAPH_SOURCES(model->graph)ccv_nnc_symbolic_graph_sources(model->graph), ccv_nnc_symbolic_graph_source_size
(model->graph)
, compiled_data->evaluate.tos, compiled_data->evaluate.to_size, &compiled_data->graph, &compiled_data->tensor_arena, &compiled_data->graph_exec_arena);
1864 ccv_array_free(tensor_binds);
1865 const uint32_t* const init_v = CCV_NNC_INIT_V(compiled_data->tensors_init.v)((uint32_t*)((uintptr_t)(compiled_data->tensors_init.v) &
~(uintptr_t)1))
;
1866 if (tensors_init && parallel_count > 1)
1867 _ccv_cnnp_model_copy_tensors(init_v, (ccv_nnc_tensor_symbol_t*)ccv_array_get(compiled_data->parameters, 0)((void*)(((char*)((compiled_data->parameters)->data)) +
(size_t)(compiled_data->parameters)->rsize * (size_t)(
0)))
, compiled_data->tensors.parameters, compiled_data->parameters->rnum, parallel_count);
1868 // If tensor is not init'ed, we need to init states first.
1869 if (_ccv_cnnp_any_to_init(compiled_data))
1870 {
1871 ccv_nnc_tensor_init_states_t tensor_init_states = {
1872 .parallel_count = parallel_count,
1873 .graph = model->graph,
1874 .compiled_data = compiled_data,
1875 .tensor_arena = compiled_data->tensor_arena
1876 };
1877 ccv_cnnp_model_init_states(model, model->graph, _ccv_cnnp_init_states_for_tensors, &tensor_init_states);
1878 }
1879 compiled_data->is_test = is_test;
1880 ccv_nnc_graph_exec_update_t update = {
1881 .parallel_count = parallel_count,
1882 .graph = model->graph,
1883 .graph_exec_arena = compiled_data->graph_exec_arena,
1884 };
1885 ccv_cnnp_model_set_is_test(model, is_test, _ccv_cnnp_cmd_update_for_execs, &update);
1886 const int evaluate_to_size = compiled_data->evaluate.to_size;
1887 compiled_data->evaluate.to_op_size = 0;
1888 ccv_array_t* const backward_from = ccv_array_new(sizeof(int), 0, 0);
1889 for (i = 0; i < evaluate_to_size; i++)
1890 {
1891 ccv_nnc_graph_exec_t const to_op = ccv_nnc_graph_exec_from_symbol(compiled_data->graph_exec_arena, compiled_data->evaluate.tos[i]);
1892 if (to_op.graph)
1893 compiled_data->evaluate.to_ops[compiled_data->evaluate.to_op_size++] = to_op;
1894 const int* tos;
1895 int to_size;
1896 ccv_nnc_graph_exec_symbol_to(model->graph, compiled_data->evaluate.tos[i], &tos, &to_size);
1897 for (j = 0; j < to_size; j++)
1898 {
1899 ccv_nnc_graph_exec_t const to_op = ccv_nnc_graph_exec_from_symbol(compiled_data->graph_exec_arena, (ccv_nnc_graph_exec_symbol_t){
1900 .d = tos[j],
1901 .graph = model->graph
1902 });
1903 if (to_op.graph)
1904 ccv_array_add_unique_int(backward_from, to_op.d);
1905 }
1906 }
1907 assert(backward_from->rnum > 0)((void) sizeof ((backward_from->rnum > 0) ? 1 : 0), __extension__
({ if (backward_from->rnum > 0) ; else __assert_fail (
"backward_from->rnum > 0", "ccv_cnnp_model.c", 1907, __extension__
__PRETTY_FUNCTION__); }))
;
1908 compiled_data->backward.from_op_size = backward_from->rnum;
1909 compiled_data->backward.from_ops = (ccv_nnc_graph_exec_t*)ccmallocmalloc(sizeof(ccv_nnc_graph_exec_t) * backward_from->rnum);
1910 for (i = 0; i < backward_from->rnum; i++)
1911 compiled_data->backward.from_ops[i] = (ccv_nnc_graph_exec_t){
1912 .d = *(int*)ccv_array_get(backward_from, i)((void*)(((char*)((backward_from)->data)) + (size_t)(backward_from
)->rsize * (size_t)(i)))
,
1913 .graph = compiled_data->graph,
1914 };
1915 // If there are any set node (to set some tensors to 0) inserted through backward pass, these won't be executed if we just do sources -> evaluate.to_ops, backward.from_ops -> destinations. We need this logic to find out these nodes and explicitly adding them to backward.from_ops.
1916 ccv_nnc_graph_exec_info_t* const exec_info = (ccv_nnc_graph_exec_info_t*)ccv_array_get(compiled_data->graph->exec_info, 0)((void*)(((char*)((compiled_data->graph->exec_info)->
data)) + (size_t)(compiled_data->graph->exec_info)->
rsize * (size_t)(0)))
;
1917 const int exec_info_size = compiled_data->graph->exec_info->rnum;
1918 uint32_t* const visited = cccalloccalloc((exec_info_size + 31) >> 5, sizeof(uint32_t));
1919 const ccv_nnc_graph_exec_t* const sources = (ccv_nnc_graph_exec_t*)ccv_array_get(compiled_data->graph->sources, 0)((void*)(((char*)((compiled_data->graph->sources)->data
)) + (size_t)(compiled_data->graph->sources)->rsize *
(size_t)(0)))
;
1920 const int source_size = compiled_data->graph->sources->rnum;
1921 ccv_nnc_graph_visit_t* visit = ccv_nnc_graph_visit_new(compiled_data->graph, exec_info, exec_info_size, sources, source_size, compiled_data->evaluate.to_ops, compiled_data->evaluate.to_op_size, 0)({ ccv_nnc_graph_visit_t* _visit_ = (ccv_nnc_graph_visit_t*)malloc
(sizeof(ccv_nnc_graph_visit_t) + sizeof(_visit_->node[0]) *
((exec_info_size) - 1)); _visit_->size = 0; do { typedef struct
{ int8_t d; int8_t r; uint16_t c; int32_t edges; } ccv_nnc_incoming_t
; int _i_, _j_; int _incoming_edges_ = 0; for (_i_ = 0; _i_ <
(exec_info_size); _i_++) _incoming_edges_ += ((exec_info)[_i_
].outgoings) ? (exec_info)[_i_].outgoings->rnum : 0; const
int _heap_mem_ = ((exec_info_size) + _incoming_edges_ > 1024
); ccv_nnc_incoming_t* _incomings_; if (_heap_mem_) _incomings_
= (ccv_nnc_incoming_t*)malloc(sizeof(ccv_nnc_incoming_t) * (
exec_info_size) + sizeof(int32_t) * ((exec_info_size) * 2 + _incoming_edges_
)); else _incomings_ = (ccv_nnc_incoming_t*)__builtin_alloca (
sizeof(ccv_nnc_incoming_t) * (exec_info_size) + sizeof(int32_t
) * ((exec_info_size) * 2 + _incoming_edges_)); memset(_incomings_
, 0, sizeof(ccv_nnc_incoming_t) * (exec_info_size)); int32_t*
_exists_[2] = { (int32_t*)(_incomings_ + (exec_info_size)), (
int32_t*)(_incomings_ + (exec_info_size)) + (exec_info_size),
}; int32_t* const _edges_ = _exists_[1] + (exec_info_size); for
(_i_ = 0; _i_ < (source_size); _i_++) { ((void) sizeof ((
(sources)[_i_].graph == compiled_data->graph) ? 1 : 0), __extension__
({ if ((sources)[_i_].graph == compiled_data->graph) ; else
__assert_fail ("(sources)[_i_].graph == compiled_data->graph"
, "ccv_cnnp_model.c", 1921, __extension__ __PRETTY_FUNCTION__
); })); _incomings_[(sources)[_i_].d].r = 1; _exists_[0][_i_]
= (sources)[_i_].d; } int _exist_size_[2] = { (source_size),
0, }; int _p_ = 0, _q_ = 1; while (_exist_size_[_p_] > 0)
{ _exist_size_[_q_] = 0; for (_i_ = 0; _i_ < _exist_size_
[_p_]; _i_++) { const int32_t _idx_ = _exists_[_p_][_i_]; if (
_incomings_[_idx_].r != 1) continue; _incomings_[_idx_].r = 2
; if ((exec_info)[_idx_].outgoings) for (_j_ = 0; _j_ < (exec_info
)[_idx_].outgoings->rnum; _j_++) { const int d = *(int*)((
void*)(((char*)(((exec_info)[_idx_].outgoings)->data)) + (
size_t)((exec_info)[_idx_].outgoings)->rsize * (size_t)(_j_
))); ++_incomings_[d].c; if (_incomings_[d].r != 0) continue;
_incomings_[d].r = 1; ((void) sizeof ((_exist_size_[_q_] <
(exec_info_size)) ? 1 : 0), __extension__ ({ if (_exist_size_
[_q_] < (exec_info_size)) ; else __assert_fail ("_exist_size_[_q_] < (exec_info_size)"
, "ccv_cnnp_model.c", 1921, __extension__ __PRETTY_FUNCTION__
); })); _exists_[_q_][_exist_size_[_q_]] = d; ++_exist_size_[
_q_]; } } ((_i_) = (_p_), (_p_) = (_q_), (_q_) = (_i_)); } for
(_i_ = 0; _i_ < (source_size); _i_++) { ((void) sizeof ((
(sources)[_i_].graph == compiled_data->graph) ? 1 : 0), __extension__
({ if ((sources)[_i_].graph == compiled_data->graph) ; else
__assert_fail ("(sources)[_i_].graph == compiled_data->graph"
, "ccv_cnnp_model.c", 1921, __extension__ __PRETTY_FUNCTION__
); })); _incomings_[(sources)[_i_].d].r = 3; _exists_[0][_i_]
= (sources)[_i_].d; } _exist_size_[0] = (source_size); _exist_size_
[1] = 0; _p_ = 0, _q_ = 1; int _bump_ = 1; while (_exist_size_
[_p_] > 0) { _exist_size_[_q_] = 0; for (_i_ = 0; _i_ <
_exist_size_[_p_]; _i_++) { const int32_t _idx_ = _exists_[_p_
][_i_]; if (_incomings_[_idx_].r != 3) continue; _incomings_[
_idx_].r = 4; if ((exec_info)[_idx_].outgoings) for (_j_ = 0;
_j_ < (exec_info)[_idx_].outgoings->rnum; _j_++) { const
int d = *(int*)((void*)(((char*)(((exec_info)[_idx_].outgoings
)->data)) + (size_t)((exec_info)[_idx_].outgoings)->rsize
* (size_t)(_j_))); if (_incomings_[d].edges == 0) { _incomings_
[d].edges = _bump_; _bump_ += _incomings_[d].c; _incomings_[d
].c = 0; } _edges_[_incomings_[d].edges - 1 + _incomings_[d].
c] = _idx_; ++_incomings_[d].c; if (_incomings_[d].r != 2) continue
; _incomings_[d].r = 3; ((void) sizeof ((_exist_size_[_q_] <
(exec_info_size)) ? 1 : 0), __extension__ ({ if (_exist_size_
[_q_] < (exec_info_size)) ; else __assert_fail ("_exist_size_[_q_] < (exec_info_size)"
, "ccv_cnnp_model.c", 1921, __extension__ __PRETTY_FUNCTION__
); })); _exists_[_q_][_exist_size_[_q_]] = d; ++_exist_size_[
_q_]; } } ((_i_) = (_p_), (_p_) = (_q_), (_q_) = (_i_)); } for
(_i_ = 0; _i_ < (compiled_data->evaluate.to_op_size); _i_
++) { ((void) sizeof (((compiled_data->evaluate.to_ops)[_i_
].graph == compiled_data->graph) ? 1 : 0), __extension__ (
{ if ((compiled_data->evaluate.to_ops)[_i_].graph == compiled_data
->graph) ; else __assert_fail ("(compiled_data->evaluate.to_ops)[_i_].graph == compiled_data->graph"
, "ccv_cnnp_model.c", 1921, __extension__ __PRETTY_FUNCTION__
); })); _incomings_[(compiled_data->evaluate.to_ops)[_i_].
d].r = 5; _exists_[0][_i_] = (compiled_data->evaluate.to_ops
)[_i_].d; } _exist_size_[0] = (compiled_data->evaluate.to_op_size
); _exist_size_[1] = 0; _p_ = 0, _q_ = 1; while (_exist_size_
[_p_] > 0) { _exist_size_[_q_] = 0; for (_i_ = 0; _i_ <
_exist_size_[_p_]; _i_++) { const int32_t _idx_ = _exists_[_p_
][_i_]; if (_incomings_[_idx_].r != 5) continue; _incomings_[
_idx_].r = 6; if (_incomings_[_idx_].edges > 0) for (_j_ =
0; _j_ < _incomings_[_idx_].c; _j_++) { const int d = _edges_
[_incomings_[_idx_].edges - 1 + _j_]; if (_incomings_[d].r !=
4) continue; _incomings_[d].r = 5; ((void) sizeof ((_exist_size_
[_q_] < (exec_info_size)) ? 1 : 0), __extension__ ({ if (_exist_size_
[_q_] < (exec_info_size)) ; else __assert_fail ("_exist_size_[_q_] < (exec_info_size)"
, "ccv_cnnp_model.c", 1921, __extension__ __PRETTY_FUNCTION__
); })); _exists_[_q_][_exist_size_[_q_]] = d; ++_exist_size_[
_q_]; } } ((_i_) = (_p_), (_p_) = (_q_), (_q_) = (_i_)); } for
(_i_ = 0; _i_ < (compiled_data->evaluate.to_op_size); _i_
++) { ((void) sizeof (((compiled_data->evaluate.to_ops)[_i_
].graph == compiled_data->graph) ? 1 : 0), __extension__ (
{ if ((compiled_data->evaluate.to_ops)[_i_].graph == compiled_data
->graph) ; else __assert_fail ("(compiled_data->evaluate.to_ops)[_i_].graph == compiled_data->graph"
, "ccv_cnnp_model.c", 1921, __extension__ __PRETTY_FUNCTION__
); })); _incomings_[(compiled_data->evaluate.to_ops)[_i_].
d].d = 1; } for (_i_ = 0; _i_ < (source_size); _i_++) { ((
void) sizeof (((sources)[_i_].graph == compiled_data->graph
) ? 1 : 0), __extension__ ({ if ((sources)[_i_].graph == compiled_data
->graph) ; else __assert_fail ("(sources)[_i_].graph == compiled_data->graph"
, "ccv_cnnp_model.c", 1921, __extension__ __PRETTY_FUNCTION__
); })); _exists_[0][_i_] = (sources)[_i_].d; } _p_ = 0; _q_ =
1; _exist_size_[0] = (source_size); _exist_size_[1] = 0; int
_d_ = 0; while (_exist_size_[_p_] > 0) { _exist_size_[_q_
] = 0; for (_i_ = 0; _i_ < _exist_size_[_p_];) { const int32_t
_idx_ = _exists_[_p_][_i_]; _visit_->node[_visit_->size
].index = ((_idx_)); _visit_->node[_visit_->size].term =
((_incomings_[_idx_].d)); ++_visit_->size;; if (_incomings_
[_idx_].d) { ++_d_; _incomings_[_idx_].r = 7; } if ((exec_info
)[_idx_].outgoings) { if ((exec_info)[_idx_].outgoings->rnum
== 1) { const int d = *(int*)((void*)(((char*)(((exec_info)[
_idx_].outgoings)->data)) + (size_t)((exec_info)[_idx_].outgoings
)->rsize * (size_t)(0))); --_incomings_[d].c; if (_incomings_
[d].c == 0 && _incomings_[d].r == 6 && _d_ <
(compiled_data->evaluate.to_op_size)) { _exists_[_p_][_i_
] = d; continue; } } else for (_j_ = 0; _j_ < (exec_info)[
_idx_].outgoings->rnum; _j_++) { const int d = *(int*)((void
*)(((char*)(((exec_info)[_idx_].outgoings)->data)) + (size_t
)((exec_info)[_idx_].outgoings)->rsize * (size_t)(_j_))); --
_incomings_[d].c; if (_incomings_[d].c == 0 && _incomings_
[d].r == 6 && _d_ < (compiled_data->evaluate.to_op_size
)) { ((void) sizeof ((_exist_size_[_q_] < (exec_info_size)
) ? 1 : 0), __extension__ ({ if (_exist_size_[_q_] < (exec_info_size
)) ; else __assert_fail ("_exist_size_[_q_] < (exec_info_size)"
, "ccv_cnnp_model.c", 1921, __extension__ __PRETTY_FUNCTION__
); })); _exists_[_q_][_exist_size_[_q_]] = d; ++_exist_size_[
_q_]; } } } ++_i_; } ((_i_) = (_p_), (_p_) = (_q_), (_q_) = (
_i_)); } for (_i_ = 0; _i_ < (compiled_data->evaluate.to_op_size
); _i_++) { ((void) sizeof (((compiled_data->evaluate.to_ops
)[_i_].graph == compiled_data->graph) ? 1 : 0), __extension__
({ if ((compiled_data->evaluate.to_ops)[_i_].graph == compiled_data
->graph) ; else __assert_fail ("(compiled_data->evaluate.to_ops)[_i_].graph == compiled_data->graph"
, "ccv_cnnp_model.c", 1921, __extension__ __PRETTY_FUNCTION__
); })); if (_incomings_[(compiled_data->evaluate.to_ops)[_i_
].d].r == 7) continue; if (!(0)) { ((void) sizeof ((_incomings_
[(compiled_data->evaluate.to_ops)[_i_].d].c == 0) ? 1 : 0)
, __extension__ ({ if (_incomings_[(compiled_data->evaluate
.to_ops)[_i_].d].c == 0) ; else __assert_fail ("_incomings_[(compiled_data->evaluate.to_ops)[_i_].d].c == 0"
, "ccv_cnnp_model.c", 1921, __extension__ __PRETTY_FUNCTION__
); })); } else if (_incomings_[(compiled_data->evaluate.to_ops
)[_i_].d].c > 0) continue; _visit_->node[_visit_->size
].index = (((compiled_data->evaluate.to_ops)[_i_].d)); _visit_
->node[_visit_->size].term = ((_incomings_[(compiled_data
->evaluate.to_ops)[_i_].d].d)); ++_visit_->size;; } if (
_heap_mem_) free(_incomings_); } while (0);; ((void) sizeof (
(_visit_->size <= (exec_info_size)) ? 1 : 0), __extension__
({ if (_visit_->size <= (exec_info_size)) ; else __assert_fail
("_visit_->size <= (exec_info_size)", "ccv_cnnp_model.c"
, 1921, __extension__ __PRETTY_FUNCTION__); })); _visit_; })
;
1922 ccv_nnc_graph_visit_for(visit, exec_info, node, idx){ int _i_; for (_i_ = 0; _i_ < (visit)->size; _i_++) { const
int idx __attribute__((unused)) = (visit)->node[_i_].index
; const int _node_unused_ __attribute__((unused)) = (visit)->
node[_i_].term; typeof ((exec_info)) const node __attribute__
((unused)) = (exec_info) + idx;
{
1923 visited[(idx >> 5)] |= (1u << (idx & 31));
1924 } ccv_nnc_graph_visit_endfor} }
1925 ccv_nnc_graph_visit_free(visit);
1926 const ccv_nnc_graph_exec_t* const destinations = (ccv_nnc_graph_exec_t*)ccv_array_get(compiled_data->graph->destinations, 0)((void*)(((char*)((compiled_data->graph->destinations)->
data)) + (size_t)(compiled_data->graph->destinations)->
rsize * (size_t)(0)))
;
1927 const int destination_size = compiled_data->graph->destinations->rnum;
1928 visit = ccv_nnc_graph_visit_new(compiled_data->graph, exec_info, exec_info_size, compiled_data->backward.from_ops, compiled_data->backward.from_op_size, destinations, destination_size, 0)({ ccv_nnc_graph_visit_t* _visit_ = (ccv_nnc_graph_visit_t*)malloc
(sizeof(ccv_nnc_graph_visit_t) + sizeof(_visit_->node[0]) *
((exec_info_size) - 1)); _visit_->size = 0; do { typedef struct
{ int8_t d; int8_t r; uint16_t c; int32_t edges; } ccv_nnc_incoming_t
; int _i_, _j_; int _incoming_edges_ = 0; for (_i_ = 0; _i_ <
(exec_info_size); _i_++) _incoming_edges_ += ((exec_info)[_i_
].outgoings) ? (exec_info)[_i_].outgoings->rnum : 0; const
int _heap_mem_ = ((exec_info_size) + _incoming_edges_ > 1024
); ccv_nnc_incoming_t* _incomings_; if (_heap_mem_) _incomings_
= (ccv_nnc_incoming_t*)malloc(sizeof(ccv_nnc_incoming_t) * (
exec_info_size) + sizeof(int32_t) * ((exec_info_size) * 2 + _incoming_edges_
)); else _incomings_ = (ccv_nnc_incoming_t*)__builtin_alloca (
sizeof(ccv_nnc_incoming_t) * (exec_info_size) + sizeof(int32_t
) * ((exec_info_size) * 2 + _incoming_edges_)); memset(_incomings_
, 0, sizeof(ccv_nnc_incoming_t) * (exec_info_size)); int32_t*
_exists_[2] = { (int32_t*)(_incomings_ + (exec_info_size)), (
int32_t*)(_incomings_ + (exec_info_size)) + (exec_info_size),
}; int32_t* const _edges_ = _exists_[1] + (exec_info_size); for
(_i_ = 0; _i_ < (compiled_data->backward.from_op_size)
; _i_++) { ((void) sizeof (((compiled_data->backward.from_ops
)[_i_].graph == compiled_data->graph) ? 1 : 0), __extension__
({ if ((compiled_data->backward.from_ops)[_i_].graph == compiled_data
->graph) ; else __assert_fail ("(compiled_data->backward.from_ops)[_i_].graph == compiled_data->graph"
, "ccv_cnnp_model.c", 1928, __extension__ __PRETTY_FUNCTION__
); })); _incomings_[(compiled_data->backward.from_ops)[_i_
].d].r = 1; _exists_[0][_i_] = (compiled_data->backward.from_ops
)[_i_].d; } int _exist_size_[2] = { (compiled_data->backward
.from_op_size), 0, }; int _p_ = 0, _q_ = 1; while (_exist_size_
[_p_] > 0) { _exist_size_[_q_] = 0; for (_i_ = 0; _i_ <
_exist_size_[_p_]; _i_++) { const int32_t _idx_ = _exists_[_p_
][_i_]; if (_incomings_[_idx_].r != 1) continue; _incomings_[
_idx_].r = 2; if ((exec_info)[_idx_].outgoings) for (_j_ = 0;
_j_ < (exec_info)[_idx_].outgoings->rnum; _j_++) { const
int d = *(int*)((void*)(((char*)(((exec_info)[_idx_].outgoings
)->data)) + (size_t)((exec_info)[_idx_].outgoings)->rsize
* (size_t)(_j_))); ++_incomings_[d].c; if (_incomings_[d].r !=
0) continue; _incomings_[d].r = 1; ((void) sizeof ((_exist_size_
[_q_] < (exec_info_size)) ? 1 : 0), __extension__ ({ if (_exist_size_
[_q_] < (exec_info_size)) ; else __assert_fail ("_exist_size_[_q_] < (exec_info_size)"
, "ccv_cnnp_model.c", 1928, __extension__ __PRETTY_FUNCTION__
); })); _exists_[_q_][_exist_size_[_q_]] = d; ++_exist_size_[
_q_]; } } ((_i_) = (_p_), (_p_) = (_q_), (_q_) = (_i_)); } for
(_i_ = 0; _i_ < (compiled_data->backward.from_op_size)
; _i_++) { ((void) sizeof (((compiled_data->backward.from_ops
)[_i_].graph == compiled_data->graph) ? 1 : 0), __extension__
({ if ((compiled_data->backward.from_ops)[_i_].graph == compiled_data
->graph) ; else __assert_fail ("(compiled_data->backward.from_ops)[_i_].graph == compiled_data->graph"
, "ccv_cnnp_model.c", 1928, __extension__ __PRETTY_FUNCTION__
); })); _incomings_[(compiled_data->backward.from_ops)[_i_
].d].r = 3; _exists_[0][_i_] = (compiled_data->backward.from_ops
)[_i_].d; } _exist_size_[0] = (compiled_data->backward.from_op_size
); _exist_size_[1] = 0; _p_ = 0, _q_ = 1; int _bump_ = 1; while
(_exist_size_[_p_] > 0) { _exist_size_[_q_] = 0; for (_i_
= 0; _i_ < _exist_size_[_p_]; _i_++) { const int32_t _idx_
= _exists_[_p_][_i_]; if (_incomings_[_idx_].r != 3) continue
; _incomings_[_idx_].r = 4; if ((exec_info)[_idx_].outgoings)
for (_j_ = 0; _j_ < (exec_info)[_idx_].outgoings->rnum
; _j_++) { const int d = *(int*)((void*)(((char*)(((exec_info
)[_idx_].outgoings)->data)) + (size_t)((exec_info)[_idx_].
outgoings)->rsize * (size_t)(_j_))); if (_incomings_[d].edges
== 0) { _incomings_[d].edges = _bump_; _bump_ += _incomings_
[d].c; _incomings_[d].c = 0; } _edges_[_incomings_[d].edges -
1 + _incomings_[d].c] = _idx_; ++_incomings_[d].c; if (_incomings_
[d].r != 2) continue; _incomings_[d].r = 3; ((void) sizeof ((
_exist_size_[_q_] < (exec_info_size)) ? 1 : 0), __extension__
({ if (_exist_size_[_q_] < (exec_info_size)) ; else __assert_fail
("_exist_size_[_q_] < (exec_info_size)", "ccv_cnnp_model.c"
, 1928, __extension__ __PRETTY_FUNCTION__); })); _exists_[_q_
][_exist_size_[_q_]] = d; ++_exist_size_[_q_]; } } ((_i_) = (
_p_), (_p_) = (_q_), (_q_) = (_i_)); } for (_i_ = 0; _i_ <
(destination_size); _i_++) { ((void) sizeof (((destinations)
[_i_].graph == compiled_data->graph) ? 1 : 0), __extension__
({ if ((destinations)[_i_].graph == compiled_data->graph)
; else __assert_fail ("(destinations)[_i_].graph == compiled_data->graph"
, "ccv_cnnp_model.c", 1928, __extension__ __PRETTY_FUNCTION__
); })); _incomings_[(destinations)[_i_].d].r = 5; _exists_[0]
[_i_] = (destinations)[_i_].d; } _exist_size_[0] = (destination_size
); _exist_size_[1] = 0; _p_ = 0, _q_ = 1; while (_exist_size_
[_p_] > 0) { _exist_size_[_q_] = 0; for (_i_ = 0; _i_ <
_exist_size_[_p_]; _i_++) { const int32_t _idx_ = _exists_[_p_
][_i_]; if (_incomings_[_idx_].r != 5) continue; _incomings_[
_idx_].r = 6; if (_incomings_[_idx_].edges > 0) for (_j_ =
0; _j_ < _incomings_[_idx_].c; _j_++) { const int d = _edges_
[_incomings_[_idx_].edges - 1 + _j_]; if (_incomings_[d].r !=
4) continue; _incomings_[d].r = 5; ((void) sizeof ((_exist_size_
[_q_] < (exec_info_size)) ? 1 : 0), __extension__ ({ if (_exist_size_
[_q_] < (exec_info_size)) ; else __assert_fail ("_exist_size_[_q_] < (exec_info_size)"
, "ccv_cnnp_model.c", 1928, __extension__ __PRETTY_FUNCTION__
); })); _exists_[_q_][_exist_size_[_q_]] = d; ++_exist_size_[
_q_]; } } ((_i_) = (_p_), (_p_) = (_q_), (_q_) = (_i_)); } for
(_i_ = 0; _i_ < (destination_size); _i_++) { ((void) sizeof
(((destinations)[_i_].graph == compiled_data->graph) ? 1 :
0), __extension__ ({ if ((destinations)[_i_].graph == compiled_data
->graph) ; else __assert_fail ("(destinations)[_i_].graph == compiled_data->graph"
, "ccv_cnnp_model.c", 1928, __extension__ __PRETTY_FUNCTION__
); })); _incomings_[(destinations)[_i_].d].d = 1; } for (_i_ =
0; _i_ < (compiled_data->backward.from_op_size); _i_++
) { ((void) sizeof (((compiled_data->backward.from_ops)[_i_
].graph == compiled_data->graph) ? 1 : 0), __extension__ (
{ if ((compiled_data->backward.from_ops)[_i_].graph == compiled_data
->graph) ; else __assert_fail ("(compiled_data->backward.from_ops)[_i_].graph == compiled_data->graph"
, "ccv_cnnp_model.c", 1928, __extension__ __PRETTY_FUNCTION__
); })); _exists_[0][_i_] = (compiled_data->backward.from_ops
)[_i_].d; } _p_ = 0; _q_ = 1; _exist_size_[0] = (compiled_data
->backward.from_op_size); _exist_size_[1] = 0; int _d_ = 0
; while (_exist_size_[_p_] > 0) { _exist_size_[_q_] = 0; for
(_i_ = 0; _i_ < _exist_size_[_p_];) { const int32_t _idx_
= _exists_[_p_][_i_]; _visit_->node[_visit_->size].index
= ((_idx_)); _visit_->node[_visit_->size].term = ((_incomings_
[_idx_].d)); ++_visit_->size;; if (_incomings_[_idx_].d) {
++_d_; _incomings_[_idx_].r = 7; } if ((exec_info)[_idx_].outgoings
) { if ((exec_info)[_idx_].outgoings->rnum == 1) { const int
d = *(int*)((void*)(((char*)(((exec_info)[_idx_].outgoings)->
data)) + (size_t)((exec_info)[_idx_].outgoings)->rsize * (
size_t)(0))); --_incomings_[d].c; if (_incomings_[d].c == 0 &&
_incomings_[d].r == 6 && _d_ < (destination_size)
) { _exists_[_p_][_i_] = d; continue; } } else for (_j_ = 0; _j_
< (exec_info)[_idx_].outgoings->rnum; _j_++) { const int
d = *(int*)((void*)(((char*)(((exec_info)[_idx_].outgoings)->
data)) + (size_t)((exec_info)[_idx_].outgoings)->rsize * (
size_t)(_j_))); --_incomings_[d].c; if (_incomings_[d].c == 0
&& _incomings_[d].r == 6 && _d_ < (destination_size
)) { ((void) sizeof ((_exist_size_[_q_] < (exec_info_size)
) ? 1 : 0), __extension__ ({ if (_exist_size_[_q_] < (exec_info_size
)) ; else __assert_fail ("_exist_size_[_q_] < (exec_info_size)"
, "ccv_cnnp_model.c", 1928, __extension__ __PRETTY_FUNCTION__
); })); _exists_[_q_][_exist_size_[_q_]] = d; ++_exist_size_[
_q_]; } } } ++_i_; } ((_i_) = (_p_), (_p_) = (_q_), (_q_) = (
_i_)); } for (_i_ = 0; _i_ < (destination_size); _i_++) { (
(void) sizeof (((destinations)[_i_].graph == compiled_data->
graph) ? 1 : 0), __extension__ ({ if ((destinations)[_i_].graph
== compiled_data->graph) ; else __assert_fail ("(destinations)[_i_].graph == compiled_data->graph"
, "ccv_cnnp_model.c", 1928, __extension__ __PRETTY_FUNCTION__
); })); if (_incomings_[(destinations)[_i_].d].r == 7) continue
; if (!(0)) { ((void) sizeof ((_incomings_[(destinations)[_i_
].d].c == 0) ? 1 : 0), __extension__ ({ if (_incomings_[(destinations
)[_i_].d].c == 0) ; else __assert_fail ("_incomings_[(destinations)[_i_].d].c == 0"
, "ccv_cnnp_model.c", 1928, __extension__ __PRETTY_FUNCTION__
); })); } else if (_incomings_[(destinations)[_i_].d].c > 0
) continue; _visit_->node[_visit_->size].index = (((destinations
)[_i_].d)); _visit_->node[_visit_->size].term = ((_incomings_
[(destinations)[_i_].d].d)); ++_visit_->size;; } if (_heap_mem_
) free(_incomings_); } while (0);; ((void) sizeof ((_visit_->
size <= (exec_info_size)) ? 1 : 0), __extension__ ({ if (_visit_
->size <= (exec_info_size)) ; else __assert_fail ("_visit_->size <= (exec_info_size)"
, "ccv_cnnp_model.c", 1928, __extension__ __PRETTY_FUNCTION__
); })); _visit_; })
;
1929 ccv_nnc_graph_visit_for(visit, exec_info, node, idx){ int _i_; for (_i_ = 0; _i_ < (visit)->size; _i_++) { const
int idx __attribute__((unused)) = (visit)->node[_i_].index
; const int _node_unused_ __attribute__((unused)) = (visit)->
node[_i_].term; typeof ((exec_info)) const node __attribute__
((unused)) = (exec_info) + idx;
{
1930 visited[(idx >> 5)] |= (1u << (idx & 31));
1931 } ccv_nnc_graph_visit_endfor} }
1932 ccv_nnc_graph_visit_free(visit);
1933 visit = ccv_nnc_graph_visit_new(compiled_data->graph, exec_info, exec_info_size, sources, source_size, destinations, destination_size, 0)({ ccv_nnc_graph_visit_t* _visit_ = (ccv_nnc_graph_visit_t*)malloc
(sizeof(ccv_nnc_graph_visit_t) + sizeof(_visit_->node[0]) *
((exec_info_size) - 1)); _visit_->size = 0; do { typedef struct
{ int8_t d; int8_t r; uint16_t c; int32_t edges; } ccv_nnc_incoming_t
; int _i_, _j_; int _incoming_edges_ = 0; for (_i_ = 0; _i_ <
(exec_info_size); _i_++) _incoming_edges_ += ((exec_info)[_i_
].outgoings) ? (exec_info)[_i_].outgoings->rnum : 0; const
int _heap_mem_ = ((exec_info_size) + _incoming_edges_ > 1024
); ccv_nnc_incoming_t* _incomings_; if (_heap_mem_) _incomings_
= (ccv_nnc_incoming_t*)malloc(sizeof(ccv_nnc_incoming_t) * (
exec_info_size) + sizeof(int32_t) * ((exec_info_size) * 2 + _incoming_edges_
)); else _incomings_ = (ccv_nnc_incoming_t*)__builtin_alloca (
sizeof(ccv_nnc_incoming_t) * (exec_info_size) + sizeof(int32_t
) * ((exec_info_size) * 2 + _incoming_edges_)); memset(_incomings_
, 0, sizeof(ccv_nnc_incoming_t) * (exec_info_size)); int32_t*
_exists_[2] = { (int32_t*)(_incomings_ + (exec_info_size)), (
int32_t*)(_incomings_ + (exec_info_size)) + (exec_info_size),
}; int32_t* const _edges_ = _exists_[1] + (exec_info_size); for
(_i_ = 0; _i_ < (source_size); _i_++) { ((void) sizeof ((
(sources)[_i_].graph == compiled_data->graph) ? 1 : 0), __extension__
({ if ((sources)[_i_].graph == compiled_data->graph) ; else
__assert_fail ("(sources)[_i_].graph == compiled_data->graph"
, "ccv_cnnp_model.c", 1933, __extension__ __PRETTY_FUNCTION__
); })); _incomings_[(sources)[_i_].d].r = 1; _exists_[0][_i_]
= (sources)[_i_].d; } int _exist_size_[2] = { (source_size),
0, }; int _p_ = 0, _q_ = 1; while (_exist_size_[_p_] > 0)
{ _exist_size_[_q_] = 0; for (_i_ = 0; _i_ < _exist_size_
[_p_]; _i_++) { const int32_t _idx_ = _exists_[_p_][_i_]; if (
_incomings_[_idx_].r != 1) continue; _incomings_[_idx_].r = 2
; if ((exec_info)[_idx_].outgoings) for (_j_ = 0; _j_ < (exec_info
)[_idx_].outgoings->rnum; _j_++) { const int d = *(int*)((
void*)(((char*)(((exec_info)[_idx_].outgoings)->data)) + (
size_t)((exec_info)[_idx_].outgoings)->rsize * (size_t)(_j_
))); ++_incomings_[d].c; if (_incomings_[d].r != 0) continue;
_incomings_[d].r = 1; ((void) sizeof ((_exist_size_[_q_] <
(exec_info_size)) ? 1 : 0), __extension__ ({ if (_exist_size_
[_q_] < (exec_info_size)) ; else __assert_fail ("_exist_size_[_q_] < (exec_info_size)"
, "ccv_cnnp_model.c", 1933, __extension__ __PRETTY_FUNCTION__
); })); _exists_[_q_][_exist_size_[_q_]] = d; ++_exist_size_[
_q_]; } } ((_i_) = (_p_), (_p_) = (_q_), (_q_) = (_i_)); } for
(_i_ = 0; _i_ < (source_size); _i_++) { ((void) sizeof ((
(sources)[_i_].graph == compiled_data->graph) ? 1 : 0), __extension__
({ if ((sources)[_i_].graph == compiled_data->graph) ; else
__assert_fail ("(sources)[_i_].graph == compiled_data->graph"
, "ccv_cnnp_model.c", 1933, __extension__ __PRETTY_FUNCTION__
); })); _incomings_[(sources)[_i_].d].r = 3; _exists_[0][_i_]
= (sources)[_i_].d; } _exist_size_[0] = (source_size); _exist_size_
[1] = 0; _p_ = 0, _q_ = 1; int _bump_ = 1; while (_exist_size_
[_p_] > 0) { _exist_size_[_q_] = 0; for (_i_ = 0; _i_ <
_exist_size_[_p_]; _i_++) { const int32_t _idx_ = _exists_[_p_
][_i_]; if (_incomings_[_idx_].r != 3) continue; _incomings_[
_idx_].r = 4; if ((exec_info)[_idx_].outgoings) for (_j_ = 0;
_j_ < (exec_info)[_idx_].outgoings->rnum; _j_++) { const
int d = *(int*)((void*)(((char*)(((exec_info)[_idx_].outgoings
)->data)) + (size_t)((exec_info)[_idx_].outgoings)->rsize
* (size_t)(_j_))); if (_incomings_[d].edges == 0) { _incomings_
[d].edges = _bump_; _bump_ += _incomings_[d].c; _incomings_[d
].c = 0; } _edges_[_incomings_[d].edges - 1 + _incomings_[d].
c] = _idx_; ++_incomings_[d].c; if (_incomings_[d].r != 2) continue
; _incomings_[d].r = 3; ((void) sizeof ((_exist_size_[_q_] <
(exec_info_size)) ? 1 : 0), __extension__ ({ if (_exist_size_
[_q_] < (exec_info_size)) ; else __assert_fail ("_exist_size_[_q_] < (exec_info_size)"
, "ccv_cnnp_model.c", 1933, __extension__ __PRETTY_FUNCTION__
); })); _exists_[_q_][_exist_size_[_q_]] = d; ++_exist_size_[
_q_]; } } ((_i_) = (_p_), (_p_) = (_q_), (_q_) = (_i_)); } for
(_i_ = 0; _i_ < (destination_size); _i_++) { ((void) sizeof
(((destinations)[_i_].graph == compiled_data->graph) ? 1 :
0), __extension__ ({ if ((destinations)[_i_].graph == compiled_data
->graph) ; else __assert_fail ("(destinations)[_i_].graph == compiled_data->graph"
, "ccv_cnnp_model.c", 1933, __extension__ __PRETTY_FUNCTION__
); })); _incomings_[(destinations)[_i_].d].r = 5; _exists_[0]
[_i_] = (destinations)[_i_].d; } _exist_size_[0] = (destination_size
); _exist_size_[1] = 0; _p_ = 0, _q_ = 1; while (_exist_size_
[_p_] > 0) { _exist_size_[_q_] = 0; for (_i_ = 0; _i_ <
_exist_size_[_p_]; _i_++) { const int32_t _idx_ = _exists_[_p_
][_i_]; if (_incomings_[_idx_].r != 5) continue; _incomings_[
_idx_].r = 6; if (_incomings_[_idx_].edges > 0) for (_j_ =
0; _j_ < _incomings_[_idx_].c; _j_++) { const int d = _edges_
[_incomings_[_idx_].edges - 1 + _j_]; if (_incomings_[d].r !=
4) continue; _incomings_[d].r = 5; ((void) sizeof ((_exist_size_
[_q_] < (exec_info_size)) ? 1 : 0), __extension__ ({ if (_exist_size_
[_q_] < (exec_info_size)) ; else __assert_fail ("_exist_size_[_q_] < (exec_info_size)"
, "ccv_cnnp_model.c", 1933, __extension__ __PRETTY_FUNCTION__
); })); _exists_[_q_][_exist_size_[_q_]] = d; ++_exist_size_[
_q_]; } } ((_i_) = (_p_), (_p_) = (_q_), (_q_) = (_i_)); } for
(_i_ = 0; _i_ < (destination_size); _i_++) { ((void) sizeof
(((destinations)[_i_].graph == compiled_data->graph) ? 1 :
0), __extension__ ({ if ((destinations)[_i_].graph == compiled_data
->graph) ; else __assert_fail ("(destinations)[_i_].graph == compiled_data->graph"
, "ccv_cnnp_model.c", 1933, __extension__ __PRETTY_FUNCTION__
); })); _incomings_[(destinations)[_i_].d].d = 1; } for (_i_ =
0; _i_ < (source_size); _i_++) { ((void) sizeof (((sources
)[_i_].graph == compiled_data->graph) ? 1 : 0), __extension__
({ if ((sources)[_i_].graph == compiled_data->graph) ; else
__assert_fail ("(sources)[_i_].graph == compiled_data->graph"
, "ccv_cnnp_model.c", 1933, __extension__ __PRETTY_FUNCTION__
); })); _exists_[0][_i_] = (sources)[_i_].d; } _p_ = 0; _q_ =
1; _exist_size_[0] = (source_size); _exist_size_[1] = 0; int
_d_ = 0; while (_exist_size_[_p_] > 0) { _exist_size_[_q_
] = 0; for (_i_ = 0; _i_ < _exist_size_[_p_];) { const int32_t
_idx_ = _exists_[_p_][_i_]; _visit_->node[_visit_->size
].index = ((_idx_)); _visit_->node[_visit_->size].term =
((_incomings_[_idx_].d)); ++_visit_->size;; if (_incomings_
[_idx_].d) { ++_d_; _incomings_[_idx_].r = 7; } if ((exec_info
)[_idx_].outgoings) { if ((exec_info)[_idx_].outgoings->rnum
== 1) { const int d = *(int*)((void*)(((char*)(((exec_info)[
_idx_].outgoings)->data)) + (size_t)((exec_info)[_idx_].outgoings
)->rsize * (size_t)(0))); --_incomings_[d].c; if (_incomings_
[d].c == 0 && _incomings_[d].r == 6 && _d_ <
(destination_size)) { _exists_[_p_][_i_] = d; continue; } } else
for (_j_ = 0; _j_ < (exec_info)[_idx_].outgoings->rnum
; _j_++) { const int d = *(int*)((void*)(((char*)(((exec_info
)[_idx_].outgoings)->data)) + (size_t)((exec_info)[_idx_].
outgoings)->rsize * (size_t)(_j_))); --_incomings_[d].c; if
(_incomings_[d].c == 0 && _incomings_[d].r == 6 &&
_d_ < (destination_size)) { ((void) sizeof ((_exist_size_
[_q_] < (exec_info_size)) ? 1 : 0), __extension__ ({ if (_exist_size_
[_q_] < (exec_info_size)) ; else __assert_fail ("_exist_size_[_q_] < (exec_info_size)"
, "ccv_cnnp_model.c", 1933, __extension__ __PRETTY_FUNCTION__
); })); _exists_[_q_][_exist_size_[_q_]] = d; ++_exist_size_[
_q_]; } } } ++_i_; } ((_i_) = (_p_), (_p_) = (_q_), (_q_) = (
_i_)); } for (_i_ = 0; _i_ < (destination_size); _i_++) { (
(void) sizeof (((destinations)[_i_].graph == compiled_data->
graph) ? 1 : 0), __extension__ ({ if ((destinations)[_i_].graph
== compiled_data->graph) ; else __assert_fail ("(destinations)[_i_].graph == compiled_data->graph"
, "ccv_cnnp_model.c", 1933, __extension__ __PRETTY_FUNCTION__
); })); if (_incomings_[(destinations)[_i_].d].r == 7) continue
; if (!(0)) { ((void) sizeof ((_incomings_[(destinations)[_i_
].d].c == 0) ? 1 : 0), __extension__ ({ if (_incomings_[(destinations
)[_i_].d].c == 0) ; else __assert_fail ("_incomings_[(destinations)[_i_].d].c == 0"
, "ccv_cnnp_model.c", 1933, __extension__ __PRETTY_FUNCTION__
); })); } else if (_incomings_[(destinations)[_i_].d].c > 0
) continue; _visit_->node[_visit_->size].index = (((destinations
)[_i_].d)); _visit_->node[_visit_->size].term = ((_incomings_
[(destinations)[_i_].d].d)); ++_visit_->size;; } if (_heap_mem_
) free(_incomings_); } while (0);; ((void) sizeof ((_visit_->
size <= (exec_info_size)) ? 1 : 0), __extension__ ({ if (_visit_
->size <= (exec_info_size)) ; else __assert_fail ("_visit_->size <= (exec_info_size)"
, "ccv_cnnp_model.c", 1933, __extension__ __PRETTY_FUNCTION__
); })); _visit_; })
;
1934 // Find any missing nodes to be added as source. Right now, these are only set nodes.
1935 ccv_nnc_graph_visit_for(visit, exec_info, node, idx){ int _i_; for (_i_ = 0; _i_ < (visit)->size; _i_++) { const
int idx __attribute__((unused)) = (visit)->node[_i_].index
; const int _node_unused_ __attribute__((unused)) = (visit)->
node[_i_].term; typeof ((exec_info)) const node __attribute__
((unused)) = (exec_info) + idx;
{
1936 if (!(visited[(idx >> 5)] & (1u << (idx & 31))))
1937 {
1938 assert(exec_info[idx].cmd.cmd == CCV_NNC_SET_FORWARD)((void) sizeof ((exec_info[idx].cmd.cmd == CCV_NNC_SET_FORWARD
) ? 1 : 0), __extension__ ({ if (exec_info[idx].cmd.cmd == CCV_NNC_SET_FORWARD
) ; else __assert_fail ("exec_info[idx].cmd.cmd == CCV_NNC_SET_FORWARD"
, "ccv_cnnp_model.c", 1938, __extension__ __PRETTY_FUNCTION__
); }))
;
1939 if (exec_info[idx].cmd.info.blas.a[0] == 0) // Special-casing for empty out the tensor set function, not for the set grad to 1 one.
1940 ccv_array_add_unique_int(backward_from, idx);
1941 }
1942 } ccv_nnc_graph_visit_endfor} }
1943 ccv_nnc_graph_visit_free(visit);
1944 ccfreefree(visited);
1945 if (backward_from->rnum != compiled_data->backward.from_op_size) // If it doesn't match, need to redo this.
1946 {
1947 compiled_data->backward.from_op_size = backward_from->rnum;
1948 compiled_data->backward.from_ops = (ccv_nnc_graph_exec_t*)ccreallocrealloc(compiled_data->backward.from_ops, sizeof(ccv_nnc_graph_exec_t) * backward_from->rnum);
1949 for (i = 0; i < backward_from->rnum; i++)
1950 compiled_data->backward.from_ops[i] = (ccv_nnc_graph_exec_t){
1951 .d = *(int*)ccv_array_get(backward_from, i)((void*)(((char*)((backward_from)->data)) + (size_t)(backward_from
)->rsize * (size_t)(i)))
,
1952 .graph = compiled_data->graph,
1953 };
1954 }
1955 ccv_array_free(backward_from);
1956 ccv_nnc_graph_set_default_static_schedule(compiled_data->graph, compiled_data->stream_type, model->max_stream_count);
1957 ccv_nnc_graph_autotune(compiled_data->graph, model->workspace_size, 0, TRAVERSE_FULL0,0,0,0);
1958}
1959
1960void ccv_cnnp_model_dry_run(ccv_cnnp_model_t* const model, const ccv_cnnp_evaluate_param_t params, ccv_nnc_tensor_t* const* const inputs, const int input_size, ccv_nnc_tensor_t* const* const outputs, const int output_size)
1961{
1962 ccv_cnnp_compiled_data_t* const compiled_data = model->compiled_data;
1963 assert(compiled_data)((void) sizeof ((compiled_data) ? 1 : 0), __extension__ ({ if
(compiled_data) ; else __assert_fail ("compiled_data", "ccv_cnnp_model.c"
, 1963, __extension__ __PRETTY_FUNCTION__); }))
;
1964 const int parallel_count = ccv_max(model->parallel_count, 1)({ typeof (model->parallel_count) _a = (model->parallel_count
); typeof (1) _b = (1); (_a > _b) ? _a : _b; })
;
1965 assert(output_size == model->output_size * parallel_count)((void) sizeof ((output_size == model->output_size * parallel_count
) ? 1 : 0), __extension__ ({ if (output_size == model->output_size
* parallel_count) ; else __assert_fail ("output_size == model->output_size * parallel_count"
, "ccv_cnnp_model.c", 1965, __extension__ __PRETTY_FUNCTION__
); }))
;
1966 assert(input_size == model->input_size * parallel_count)((void) sizeof ((input_size == model->input_size * parallel_count
) ? 1 : 0), __extension__ ({ if (input_size == model->input_size
* parallel_count) ; else __assert_fail ("input_size == model->input_size * parallel_count"
, "ccv_cnnp_model.c", 1966, __extension__ __PRETTY_FUNCTION__
); }))
;
1967 assert(model->graph)((void) sizeof ((model->graph) ? 1 : 0), __extension__ ({ if
(model->graph) ; else __assert_fail ("model->graph", "ccv_cnnp_model.c"
, 1967, __extension__ __PRETTY_FUNCTION__); }))
;
1968 const int target_gradient_mode = _ccv_cnnp_is_disable_outgrad_all(params.disable_outgrad, model->input_size) ? CCV_CNNP_COMPILED_DATA_GRADIENT_TRAINABLES : CCV_CNNP_COMPILED_DATA_GRADIENT_TRAINABLES_AND_INPUTS;
1969 const int mode_mismatch = (params.requires_grad && (compiled_data->graph_mode != CCV_CNNP_MODEL_GRAPH_MULTISTAGE_MODE || compiled_data->gradient_mode != target_gradient_mode || compiled_data->disable_outgrad != params.disable_outgrad));
1970 if (!compiled_data->graph || mode_mismatch)
1971 {
1972 _ccv_cnnp_compiled_data_graph_free(compiled_data);
1973 if (mode_mismatch) // If mode mismatch, we need to redo the backward as well (no need to redo apply_gradients, it doesn't require target_gradient_mode or disable_outgrad.
1974 _ccv_cnnp_compiled_data_backward_free(compiled_data);
1975 if (params.requires_grad)
1976 _ccv_cnnp_model_multistage_jit_0(model, params.disable_outgrad, params.is_test, inputs, input_size, outputs, output_size);
1977 else
1978 _ccv_cnnp_model_multistage_no_grad_jit(model, inputs, input_size, outputs, output_size);
1979 } else {
1980 ccv_nnc_tensor_arena_clear_bindings(compiled_data->tensor_arena);
1981 assert((input_size % parallel_count) == 0)((void) sizeof (((input_size % parallel_count) == 0) ? 1 : 0)
, __extension__ ({ if ((input_size % parallel_count) == 0) ; else
__assert_fail ("(input_size % parallel_count) == 0", "ccv_cnnp_model.c"
, 1981, __extension__ __PRETTY_FUNCTION__); }))
;
1982 const int input_size_per_p = input_size / parallel_count;
1983 _ccv_cnnp_bind_tensors_to_arena(compiled_data->tensor_arena, model->graph, model->inputs, inputs, input_size_per_p, parallel_count);
1984 assert((output_size % parallel_count) == 0)((void) sizeof (((output_size % parallel_count) == 0) ? 1 : 0
), __extension__ ({ if ((output_size % parallel_count) == 0) ;
else __assert_fail ("(output_size % parallel_count) == 0", "ccv_cnnp_model.c"
, 1984, __extension__ __PRETTY_FUNCTION__); }))
;
1985 const int output_size_per_p = output_size / parallel_count;
1986 _ccv_cnnp_bind_tensors_to_arena(compiled_data->tensor_arena, model->graph, model->outputs, outputs, output_size_per_p, parallel_count);
1987 }
1988 if (compiled_data->is_test != params.is_test)
1989 {
1990 compiled_data->is_test = params.is_test;
1991 ccv_nnc_graph_exec_update_t update = {
1992 .parallel_count = parallel_count,
1993 .graph = model->graph,
1994 .graph_exec_arena = compiled_data->graph_exec_arena,
1995 };
1996 ccv_cnnp_model_set_is_test(model, params.is_test, _ccv_cnnp_cmd_update_for_execs, &update);
1997 }
1998}
1999
2000void ccv_cnnp_model_evaluate(ccv_cnnp_model_t* const model, const ccv_cnnp_evaluate_param_t params, ccv_nnc_tensor_t* const* const inputs, const int input_size, ccv_nnc_tensor_t* const* const outputs, const int output_size, ccv_nnc_tensor_tape_t* const tensor_tape, ccv_nnc_stream_context_t* const stream_context)
2001{
2002 ccv_cnnp_compiled_data_t* const compiled_data = model->compiled_data;
2003 assert(compiled_data)((void) sizeof ((compiled_data) ? 1 : 0), __extension__ ({ if
(compiled_data) ; else __assert_fail ("compiled_data", "ccv_cnnp_model.c"
, 2003, __extension__ __PRETTY_FUNCTION__); }))
;
2004 ccv_cnnp_model_dry_run(model, params, inputs, input_size, outputs, output_size);
2005 if (compiled_data->graph_mode == CCV_CNNP_MODEL_GRAPH_MULTISTAGE_MODE_NO_GRAD)
2006 ccv_nnc_graph_run_with_schedule(compiled_data->graph, 0, 0, tensor_tape, stream_context);
2007 else {
2008 if (!compiled_data->evaluate.schedule)
2009 compiled_data->evaluate.schedule = ccv_nnc_graph_static_schedule_new(compiled_data->graph, compiled_data->stream_type, model->max_stream_count, 0, 0, compiled_data->evaluate.to_ops, compiled_data->evaluate.to_op_size);
2010 ccv_nnc_graph_run_with_schedule(compiled_data->graph, 0, compiled_data->evaluate.schedule, tensor_tape, stream_context);
2011 }
2012}
2013
2014// Compile the graph to run ccv_cnnp_model_backward after ccv_cnnp_model_evaluate with requires_grad = true (MULTISTAGE_MODE).
2015// Particularly, this method compiles the accumulator graph.
2016static void _ccv_cnnp_model_multistage_jit_1(ccv_cnnp_model_t* const model)
2017{
2018 ccv_cnnp_compiled_data_t* const compiled_data = model->compiled_data;
2019 assert(compiled_data)((void) sizeof ((compiled_data) ? 1 : 0), __extension__ ({ if
(compiled_data) ; else __assert_fail ("compiled_data", "ccv_cnnp_model.c"
, 2019, __extension__ __PRETTY_FUNCTION__); }))
;
2020 assert(compiled_data->graph_mode == CCV_CNNP_MODEL_GRAPH_MULTISTAGE_MODE)((void) sizeof ((compiled_data->graph_mode == CCV_CNNP_MODEL_GRAPH_MULTISTAGE_MODE
) ? 1 : 0), __extension__ ({ if (compiled_data->graph_mode
== CCV_CNNP_MODEL_GRAPH_MULTISTAGE_MODE) ; else __assert_fail
("compiled_data->graph_mode == CCV_CNNP_MODEL_GRAPH_MULTISTAGE_MODE"
, "ccv_cnnp_model.c", 2020, __extension__ __PRETTY_FUNCTION__
); }))
;
2021 ccv_nnc_symbolic_graph_t* accum = ccv_nnc_symbolic_graph_new();
2022 const int parallel_count = ccv_max(model->parallel_count, 1)({ typeof (model->parallel_count) _a = (model->parallel_count
); typeof (1) _b = (1); (_a > _b) ? _a : _b; })
;
2023 const int parameter_size = compiled_data->parameters->rnum;
2024 int i, j;
2025 compiled_data->backward.gradients = (ccv_nnc_tensor_symbol_t*)ccmallocmalloc(sizeof(ccv_nnc_tensor_symbol_t) * parameter_size * parallel_count * 3);
2026 compiled_data->backward.accum_gradients = compiled_data->backward.gradients + parameter_size * parallel_count;
2027 compiled_data->backward.updated_accum_gradients = compiled_data->backward.accum_gradients + parameter_size * parallel_count;
2028 for (i = 0; i < parameter_size; i++)
2029 for (j = 0; j < parallel_count; j++)
2030 if (compiled_data->tensors.gradients[i + j * parameter_size])
2031 {
2032 const ccv_nnc_tensor_param_t info = compiled_data->tensors.gradients[i + j * parameter_size]->info;
2033 // Now, the old gradient is the accumulated gradient, getting new gradient tensor setup so we can collect them.
2034 compiled_data->tensors.accum_gradients[i + j * parameter_size] = compiled_data->tensors.gradients[i + j * parameter_size];
2035 compiled_data->tensors.gradients[i + j * parameter_size] = ccv_nnc_tensor_new(0, info, 0);
2036 ccv_nnc_tensor_symbol_t inputs[2];
2037 inputs[0] = compiled_data->backward.accum_gradients[i + j * parameter_size] = ccv_nnc_tensor_symbol_new(accum, info, 0);
2038 inputs[1] = compiled_data->backward.gradients[i + j * parameter_size] = ccv_nnc_tensor_symbol_new(accum, info, 0);
2039 ccv_nnc_tensor_symbol_t output = compiled_data->backward.updated_accum_gradients[i + j * parameter_size] = ccv_nnc_tensor_symbol_new(accum, info, 0);
2040 ccv_nnc_graph_exec_symbol_new(accum, CMD_EWSUM_FORWARD()ccv_nnc_cmd(CCV_NNC_EWSUM_FORWARD, 0, ccv_nnc_cmd_auto, 0), inputs, 2, &output, 1, 0);
2041 } else {
2042 compiled_data->backward.accum_gradients[i + j * parameter_size] = NO_TENSOR_SYMBOL(const ccv_nnc_tensor_symbol_t){.d = CCV_NNC_NO_TENSOR_SYMBOL
}
;
2043 compiled_data->backward.gradients[i + j * parameter_size] = NO_TENSOR_SYMBOL(const ccv_nnc_tensor_symbol_t){.d = CCV_NNC_NO_TENSOR_SYMBOL
}
;
2044 compiled_data->backward.updated_accum_gradients[i + j * parameter_size] = NO_TENSOR_SYMBOL(const ccv_nnc_tensor_symbol_t){.d = CCV_NNC_NO_TENSOR_SYMBOL
}
;
2045 }
2046 ccv_nnc_graph_exec_symbol_autogen(accum, 0, 0, CCV_NNC_AUTOGEN_ALL_EXECS | CCV_NNC_AUTOGEN_SOURCES_AND_DESTINATIONS);
2047 if (ccv_nnc_symbolic_graph_source_size(accum) == 0)
2048 {
2049 ccv_nnc_symbolic_graph_free(accum);
2050 // Create empty graph.
2051 compiled_data->backward.accum = ccv_nnc_graph_new();
2052 ccv_nnc_graph_topsort(compiled_data->backward.accum, 0, 0);
2053 return;
2054 }
2055 ccv_array_t* const tensor_binds = ccv_array_new(sizeof(ccv_nnc_tensor_bind_t), 0, 0);
2056 _ccv_cnnp_model_bind_tensors(accum, compiled_data->backward.accum_gradients, compiled_data->tensors.accum_gradients, parameter_size * parallel_count, 1, tensor_binds);
2057 _ccv_cnnp_model_bind_tensors(accum, compiled_data->backward.gradients, compiled_data->tensors.gradients, parameter_size * parallel_count, 1, tensor_binds);
2058 _ccv_cnnp_model_bind_tensors(accum, compiled_data->backward.updated_accum_gradients, compiled_data->tensors.accum_gradients, parameter_size * parallel_count, 1, tensor_binds);
2059 ccv_nnc_symbolic_graph_compile(accum, compiled_data->compile_params, (ccv_nnc_tensor_bind_t*)ccv_array_get(tensor_binds, 0)((void*)(((char*)((tensor_binds)->data)) + (size_t)(tensor_binds
)->rsize * (size_t)(0)))
, tensor_binds->rnum, 0, 0, SYMBOLIC_GRAPH_SOURCES(accum)ccv_nnc_symbolic_graph_sources(accum), ccv_nnc_symbolic_graph_source_size
(accum)
, SYMBOLIC_GRAPH_DESTINATIONS(accum)ccv_nnc_symbolic_graph_destinations(accum), ccv_nnc_symbolic_graph_destination_size
(accum)
, &compiled_data->backward.accum, &compiled_data->backward.tensor_arena, &compiled_data->backward.graph_exec_arena);
2060 ccv_nnc_symbolic_graph_free(accum);
2061 ccv_array_free(tensor_binds);
2062 ccv_nnc_graph_set_default_static_schedule(compiled_data->backward.accum, compiled_data->stream_type, model->max_stream_count);
2063}
2064
2065void ccv_cnnp_model_backward(ccv_cnnp_model_t* const model, ccv_nnc_tensor_t* const* const ingrads, const int ingrad_size, ccv_nnc_tensor_t* const* const outgrads, const int outgrad_size, ccv_nnc_tensor_tape_t* const tensor_tape, ccv_nnc_stream_context_t* const stream_context)
2066{
2067 ccv_cnnp_compiled_data_t* const compiled_data = model->compiled_data;
2068 assert(compiled_data)((void) sizeof ((compiled_data) ? 1 : 0), __extension__ ({ if
(compiled_data) ; else __assert_fail ("compiled_data", "ccv_cnnp_model.c"
, 2068, __extension__ __PRETTY_FUNCTION__); }))
;
2069 assert(compiled_data->graph_mode == CCV_CNNP_MODEL_GRAPH_MULTISTAGE_MODE)((void) sizeof ((compiled_data->graph_mode == CCV_CNNP_MODEL_GRAPH_MULTISTAGE_MODE
) ? 1 : 0), __extension__ ({ if (compiled_data->graph_mode
== CCV_CNNP_MODEL_GRAPH_MULTISTAGE_MODE) ; else __assert_fail
("compiled_data->graph_mode == CCV_CNNP_MODEL_GRAPH_MULTISTAGE_MODE"
, "ccv_cnnp_model.c", 2069, __extension__ __PRETTY_FUNCTION__
); }))
;
2070 const int parallel_count = ccv_max(model->parallel_count, 1)({ typeof (model->parallel_count) _a = (model->parallel_count
); typeof (1) _b = (1); (_a > _b) ? _a : _b; })
;
2071 assert(ingrad_size == 0 || ingrad_size == model->output_size * parallel_count)((void) sizeof ((ingrad_size == 0 || ingrad_size == model->
output_size * parallel_count) ? 1 : 0), __extension__ ({ if (
ingrad_size == 0 || ingrad_size == model->output_size * parallel_count
) ; else __assert_fail ("ingrad_size == 0 || ingrad_size == model->output_size * parallel_count"
, "ccv_cnnp_model.c", 2071, __extension__ __PRETTY_FUNCTION__
); }))
;
2072 if (outgrad_size > 0)
2073 { assert(outgrad_size == compiled_data->outgrad_size * parallel_count)((void) sizeof ((outgrad_size == compiled_data->outgrad_size
* parallel_count) ? 1 : 0), __extension__ ({ if (outgrad_size
== compiled_data->outgrad_size * parallel_count) ; else __assert_fail
("outgrad_size == compiled_data->outgrad_size * parallel_count"
, "ccv_cnnp_model.c", 2073, __extension__ __PRETTY_FUNCTION__
); }))
; }
2074 assert(model->graph)((void) sizeof ((model->graph) ? 1 : 0), __extension__ ({ if
(model->graph) ; else __assert_fail ("model->graph", "ccv_cnnp_model.c"
, 2074, __extension__ __PRETTY_FUNCTION__); }))
;
2075 assert(compiled_data->graph)((void) sizeof ((compiled_data->graph) ? 1 : 0), __extension__
({ if (compiled_data->graph) ; else __assert_fail ("compiled_data->graph"
, "ccv_cnnp_model.c", 2075, __extension__ __PRETTY_FUNCTION__
); }))
;
2076 const int parameter_size = compiled_data->parameters->rnum;
2077 // If we need to accumulate the gradients now, do jit on accumulator.
2078 if (compiled_data->backward.count > 0)
2079 {
2080 if (!compiled_data->backward.accum)
2081 _ccv_cnnp_model_multistage_jit_1(model);
2082 else if (compiled_data->backward.count == 1) {
2083 // On this round, we need to switch accumulated gradients with gradients (so we can do accumulation properly).
2084 int i;
2085 for (i = 0; i < parameter_size * parallel_count; i++)
2086 {
2087 ccv_nnc_tensor_t* tensor;
2088 CCV_SWAP(compiled_data->tensors.accum_gradients[i], compiled_data->tensors.gradients[i], tensor)((tensor) = (compiled_data->tensors.accum_gradients[i]), (
compiled_data->tensors.accum_gradients[i]) = (compiled_data
->tensors.gradients[i]), (compiled_data->tensors.gradients
[i]) = (tensor))
;
2089 }
2090 if (compiled_data->backward.tensor_arena)
2091 {
2092 ccv_nnc_tensor_arena_clear_bindings(compiled_data->backward.tensor_arena);
2093 // Do rebind in case we messed up the binding (we switch accum_gradients and gradients).
2094 _ccv_cnnp_bind_tensors_to_arena(compiled_data->backward.tensor_arena, 0, compiled_data->backward.gradients, compiled_data->tensors.gradients, parameter_size * parallel_count, 1);
2095 _ccv_cnnp_bind_tensors_to_arena(compiled_data->backward.tensor_arena, 0, compiled_data->backward.accum_gradients, compiled_data->tensors.accum_gradients, parameter_size * parallel_count, 1);
2096 _ccv_cnnp_bind_tensors_to_arena(compiled_data->backward.tensor_arena, 0, compiled_data->backward.updated_accum_gradients, compiled_data->tensors.accum_gradients, parameter_size * parallel_count, 1);
2097 }
2098 }
2099 }
2100 const int ingrad_size_per_p = model->output_size;
2101 const int outgrad_size_per_p = compiled_data->outgrad_size;
2102 int i, j;
2103 for (i = 0; i < ingrad_size_per_p; i++)
2104 {
2105 const ccv_nnc_tensor_symbol_t ingrad = ccv_nnc_tensor_symbol_for_backward(model->graph, compiled_data->f[i]);
2106 if (!ingrad_size || !ingrads || ingrads[i] == 0)
2107 {
2108 // Set it to 1 if it is not specified.
2109 ccv_nnc_tensor_t* const ingrad_tensor = ccv_nnc_tensor_from_symbol(compiled_data->tensor_arena, ingrad);
2110 if (ingrad_tensor)
2111 ccv_nnc_cmd_exec(CMD_SET_FORWARD(1)ccv_nnc_cmd(CCV_NNC_SET_FORWARD, 0, (ccv_nnc_cmd_param_t){.size
={.dim={1,1,1}},.blas={.a={1,}}}, 0)
, ccv_nnc_no_hint, 0, 0, 0, TENSOR_LIST(ingrad_tensor)(ccv_nnc_tensor_t* []){ingrad_tensor}, (1 +1 +0 +0 +0 +0 +0 +
0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0
+0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +
0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 -1)
, stream_context);
2112 for (j = 1; j < parallel_count; j++)
2113 {
2114 ccv_nnc_tensor_t* const ingrad_tensor = ccv_nnc_tensor_from_symbol(compiled_data->tensor_arena, ccv_nnc_tensor_symbol_copy(model->graph, ingrad, j));
2115 if (ingrad_tensor)
2116 ccv_nnc_cmd_exec(CMD_SET_FORWARD(1)ccv_nnc_cmd(CCV_NNC_SET_FORWARD, 0, (ccv_nnc_cmd_param_t){.size
={.dim={1,1,1}},.blas={.a={1,}}}, 0)
, ccv_nnc_no_hint, 0, 0, 0, TENSOR_LIST(ingrad_tensor)(ccv_nnc_tensor_t* []){ingrad_tensor}, (1 +1 +0 +0 +0 +0 +0 +
0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0
+0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +
0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 -1)
, stream_context);
2117 }
2118 } else {
2119 // Make sure the length matches, in case it is an alias.
2120 assert(ccv_nnc_tensor_count(ingrads[i]->info) == ccv_nnc_tensor_count(ccv_nnc_tensor_symbol_params(model->graph, ingrad)))((void) sizeof ((ccv_nnc_tensor_count(ingrads[i]->info) ==
ccv_nnc_tensor_count(ccv_nnc_tensor_symbol_params(model->
graph, ingrad))) ? 1 : 0), __extension__ ({ if (ccv_nnc_tensor_count
(ingrads[i]->info) == ccv_nnc_tensor_count(ccv_nnc_tensor_symbol_params
(model->graph, ingrad))) ; else __assert_fail ("ccv_nnc_tensor_count(ingrads[i]->info) == ccv_nnc_tensor_count(ccv_nnc_tensor_symbol_params(model->graph, ingrad))"
, "ccv_cnnp_model.c", 2120, __extension__ __PRETTY_FUNCTION__
); }))
;
2121 ccv_nnc_tensor_bind_symbol(compiled_data->tensor_arena, ingrad, ingrads[i]);
2122 for (j = 1; j < parallel_count; j++)
2123 ccv_nnc_tensor_bind_symbol(compiled_data->tensor_arena, ccv_nnc_tensor_symbol_copy(model->graph, ingrad, j), ingrads[i + ingrad_size_per_p * j]);
2124 }
2125 }
2126 if (outgrad_size > 0)
2127 {
2128 assert(compiled_data->gradient_mode == CCV_CNNP_COMPILED_DATA_GRADIENT_TRAINABLES_AND_INPUTS && "shouldn't pass disable_outgrad to ccv_cnnp_model_evaluate before if you plan to compute outgrad")((void) sizeof ((compiled_data->gradient_mode == CCV_CNNP_COMPILED_DATA_GRADIENT_TRAINABLES_AND_INPUTS
&& "shouldn't pass disable_outgrad to ccv_cnnp_model_evaluate before if you plan to compute outgrad"
) ? 1 : 0), __extension__ ({ if (compiled_data->gradient_mode
== CCV_CNNP_COMPILED_DATA_GRADIENT_TRAINABLES_AND_INPUTS &&
"shouldn't pass disable_outgrad to ccv_cnnp_model_evaluate before if you plan to compute outgrad"
) ; else __assert_fail ("compiled_data->gradient_mode == CCV_CNNP_COMPILED_DATA_GRADIENT_TRAINABLES_AND_INPUTS && \"shouldn't pass disable_outgrad to ccv_cnnp_model_evaluate before if you plan to compute outgrad\""
, "ccv_cnnp_model.c", 2128, __extension__ __PRETTY_FUNCTION__
); }))
;
2129 for (i = 0; i < outgrad_size_per_p; i++)
2130 if (outgrads[i])
2131 {
2132 const ccv_nnc_tensor_symbol_t outgrad = compiled_data->outgrads[i];
2133 ccv_nnc_tensor_bind_symbol(compiled_data->tensor_arena, outgrad, outgrads[i]);
2134 for (j = 1; j < parallel_count; j++)
2135 ccv_nnc_tensor_bind_symbol(compiled_data->tensor_arena, ccv_nnc_tensor_symbol_copy(model->graph, outgrad, j), outgrads[i + outgrad_size_per_p * j]);
2136 }
2137 } else {
2138 assert(compiled_data->gradient_mode == CCV_CNNP_COMPILED_DATA_GRADIENT_TRAINABLES ||((void) sizeof ((compiled_data->gradient_mode == CCV_CNNP_COMPILED_DATA_GRADIENT_TRAINABLES
|| compiled_data->gradient_mode == CCV_CNNP_COMPILED_DATA_GRADIENT_TRAINABLES_AND_INPUTS
) ? 1 : 0), __extension__ ({ if (compiled_data->gradient_mode
== CCV_CNNP_COMPILED_DATA_GRADIENT_TRAINABLES || compiled_data
->gradient_mode == CCV_CNNP_COMPILED_DATA_GRADIENT_TRAINABLES_AND_INPUTS
) ; else __assert_fail ("compiled_data->gradient_mode == CCV_CNNP_COMPILED_DATA_GRADIENT_TRAINABLES || compiled_data->gradient_mode == CCV_CNNP_COMPILED_DATA_GRADIENT_TRAINABLES_AND_INPUTS"
, "ccv_cnnp_model.c", 2139, __extension__ __PRETTY_FUNCTION__
); }))
2139 compiled_data->gradient_mode == CCV_CNNP_COMPILED_DATA_GRADIENT_TRAINABLES_AND_INPUTS)((void) sizeof ((compiled_data->gradient_mode == CCV_CNNP_COMPILED_DATA_GRADIENT_TRAINABLES
|| compiled_data->gradient_mode == CCV_CNNP_COMPILED_DATA_GRADIENT_TRAINABLES_AND_INPUTS
) ? 1 : 0), __extension__ ({ if (compiled_data->gradient_mode
== CCV_CNNP_COMPILED_DATA_GRADIENT_TRAINABLES || compiled_data
->gradient_mode == CCV_CNNP_COMPILED_DATA_GRADIENT_TRAINABLES_AND_INPUTS
) ; else __assert_fail ("compiled_data->gradient_mode == CCV_CNNP_COMPILED_DATA_GRADIENT_TRAINABLES || compiled_data->gradient_mode == CCV_CNNP_COMPILED_DATA_GRADIENT_TRAINABLES_AND_INPUTS"
, "ccv_cnnp_model.c", 2139, __extension__ __PRETTY_FUNCTION__
); }))
;
2140 }
2141 // We need to rebind here because in ccv_cnnp_evaluate, we clear bindings, that will reset all bindings for the gradients.
2142 // For parameters and internals these are fine because when we clear bindings, it restores to original bindings, which are these
2143 // parameters and internals. The same cannot be said for gradients due to the accum_gradients switching.
2144 _ccv_cnnp_bind_tensors_to_arena(compiled_data->tensor_arena, model->graph, compiled_data->gradients, compiled_data->tensors.gradients, parameter_size, parallel_count);
2145 if (!compiled_data->backward.schedule)
2146 compiled_data->backward.schedule = ccv_nnc_graph_static_schedule_new(compiled_data->graph, compiled_data->stream_type, model->max_stream_count, compiled_data->backward.from_ops, compiled_data->backward.from_op_size, 0, 0);
2147 // Run the backward pass.
2148 ccv_nnc_graph_run_with_schedule(compiled_data->graph, 0, compiled_data->backward.schedule, tensor_tape, stream_context);
2149 // If we need to run accumulation round, do that now.
2150 if (compiled_data->backward.count > 0)
2151 ccv_nnc_graph_run_with_schedule(compiled_data->backward.accum, 0, 0, 0, stream_context);
2152 // Update the count, this determines whether we need to accumulate or not.
2153 ++compiled_data->backward.count;
2154}
2155
2156// Compile the graph to run ccv_cnnp_model_apply_gradients after ccv_cnnp_model_backward (MULTISTAGE_MODE).
2157// Particularly, this method compiles the parameter update graph.
2158static void _ccv_cnnp_model_multistage_jit_2(ccv_cnnp_model_t* const model)
2159{
2160 ccv_cnnp_compiled_data_t* const compiled_data = model->compiled_data;
2161 assert(compiled_data->graph_mode == CCV_CNNP_MODEL_GRAPH_MULTISTAGE_MODE)((void) sizeof ((compiled_data->graph_mode == CCV_CNNP_MODEL_GRAPH_MULTISTAGE_MODE
) ? 1 : 0), __extension__ ({ if (compiled_data->graph_mode
== CCV_CNNP_MODEL_GRAPH_MULTISTAGE_MODE) ; else __assert_fail
("compiled_data->graph_mode == CCV_CNNP_MODEL_GRAPH_MULTISTAGE_MODE"
, "ccv_cnnp_model.c", 2161, __extension__ __PRETTY_FUNCTION__
); }))
;
2162 const int parallel_count = ccv_max(model->parallel_count, 1)({ typeof (model->parallel_count) _a = (model->parallel_count
); typeof (1) _b = (1); (_a > _b) ? _a : _b; })
;
2163 const int parameter_size = compiled_data->parameters->rnum;
2164 ccv_array_t* const tensor_binds = ccv_array_new(sizeof(ccv_nnc_tensor_bind_t), 0, 0);
2165 _ccv_cnnp_model_bind_tensors(model->graph, (ccv_nnc_tensor_symbol_t*)ccv_array_get(compiled_data->parameters, 0)((void*)(((char*)((compiled_data->parameters)->data)) +
(size_t)(compiled_data->parameters)->rsize * (size_t)(
0)))
, compiled_data->tensors.parameters, parameter_size, parallel_count, tensor_binds);
2166 _ccv_cnnp_model_bind_tensors(model->graph, compiled_data->updated_parameters, compiled_data->tensors.parameters, parameter_size, parallel_count, tensor_binds);
2167 // Bind accumulated gradients.
2168 if (compiled_data->backward.count > 1)
2169 _ccv_cnnp_model_bind_tensors(model->graph, compiled_data->gradients, compiled_data->tensors.accum_gradients, parameter_size, parallel_count, tensor_binds);
2170 else
2171 _ccv_cnnp_model_bind_tensors(model->graph, compiled_data->gradients, compiled_data->tensors.gradients, parameter_size, parallel_count, tensor_binds);
2172 ccv_array_t* const apply_gradients_from = ccv_array_new(sizeof(int), 0, 0);
2173 int i, j;
2174 for (i = 0; i < compiled_data->backward.to_size; i++)
2175 {
2176 const int* tos;
2177 int to_size;
2178 ccv_nnc_graph_exec_symbol_to(model->graph, compiled_data->backward.tos[i], &tos, &to_size);
2179 for (j = 0; j < to_size; j++)
2180 {
2181 // Check if this is already show up in the backward graph, if that is the case, it won't be in the apply
2182 // gradients graph.
2183 const ccv_nnc_graph_exec_t exec = ccv_nnc_graph_exec_from_symbol(compiled_data->graph_exec_arena, (ccv_nnc_graph_exec_symbol_t){
2184 .d = tos[j],
2185 .graph = model->graph,
2186 });
2187 if (!exec.graph)
2188 ccv_array_add_unique_int(apply_gradients_from, tos[j]);
2189 }
2190 }
2191 const int from_size = apply_gradients_from->rnum;
2192 if (from_size == 0)
2193 {
2194 ccv_array_free(apply_gradients_from);
2195 ccv_array_free(tensor_binds);
2196 return;
2197 }
2198 ccv_nnc_graph_exec_symbol_t* const froms = (ccv_nnc_graph_exec_symbol_t*)ccmallocmalloc(sizeof(ccv_nnc_graph_exec_symbol_t) * from_size);
2199 for (i = 0; i < from_size; i++)
2200 froms[i] = (ccv_nnc_graph_exec_symbol_t){
2201 .d = *(int*)ccv_array_get(apply_gradients_from, i)((void*)(((char*)((apply_gradients_from)->data)) + (size_t
)(apply_gradients_from)->rsize * (size_t)(i)))
,
2202 .graph = model->graph
2203 };
2204 ccv_array_free(apply_gradients_from);
2205 // It can only ends with updates on the parameters.
2206 ccv_array_t* const tos = ccv_array_new(sizeof(ccv_nnc_graph_exec_symbol_t), parameter_size * parallel_count, 0);
2207 for (i = 0; i < parameter_size; i++)
2208 {
2209 if (compiled_data->update_nodes[i].d == CCV_NNC_NO_TENSOR_SYMBOL)
2210 continue;
2211 ccv_array_push(tos, &compiled_data->update_nodes[i]);
2212 for (j = 1; j < parallel_count; j++)
2213 {
2214 const ccv_nnc_graph_exec_symbol_t copy = ccv_nnc_graph_exec_symbol_copy(model->graph, compiled_data->update_nodes[i], j);
2215 ccv_array_push(tos, &copy);
2216 }
2217 }
2218 ccv_nnc_symbolic_graph_compile(model->graph, compiled_data->compile_params, (ccv_nnc_tensor_bind_t*)ccv_array_get(tensor_binds, 0)((void*)(((char*)((tensor_binds)->data)) + (size_t)(tensor_binds
)->rsize * (size_t)(0)))
, tensor_binds->rnum, 0, 0, froms, from_size, (ccv_nnc_graph_exec_symbol_t*)ccv_array_get(tos, 0)((void*)(((char*)((tos)->data)) + (size_t)(tos)->rsize *
(size_t)(0)))
, tos->rnum, &compiled_data->apply_gradients.graph, &compiled_data->apply_gradients.tensor_arena, &compiled_data->apply_gradients.graph_exec_arena);
2219 ccv_array_free(tos);
2220 ccv_array_free(tensor_binds);
2221 ccfreefree(froms);
2222 const int max_saved_aux_size = compiled_data->minimize.max_saved_aux_size;
2223 for (i = 0; i < max_saved_aux_size * parameter_size; i++)
2224 {
2225 // Skip on no tensor.
2226 if (compiled_data->saved_aux[i].source.d == CCV_NNC_NO_TENSOR_SYMBOL)
2227 continue;
2228 ccv_nnc_tensor_t* const tensor = ccv_nnc_tensor_from_symbol(compiled_data->apply_gradients.tensor_arena, compiled_data->saved_aux[i].source);
2229 ccv_nnc_cmd_exec(CMD_SET_FORWARD(0)ccv_nnc_cmd(CCV_NNC_SET_FORWARD, 0, (ccv_nnc_cmd_param_t){.size
={.dim={1,1,1}},.blas={.a={0,}}}, 0)
, ccv_nnc_no_hint, 0, 0, 0, &tensor, 1, 0);
2230 for (j = 1; j < parallel_count; j++)
2231 {
2232 ccv_nnc_tensor_t* const copy = ccv_nnc_tensor_from_symbol(compiled_data->apply_gradients.tensor_arena, ccv_nnc_tensor_symbol_copy(model->graph, compiled_data->saved_aux[i].source, j));
2233 if (copy)
2234 ccv_nnc_cmd_exec(CMD_SET_FORWARD(0)ccv_nnc_cmd(CCV_NNC_SET_FORWARD, 0, (ccv_nnc_cmd_param_t){.size
={.dim={1,1,1}},.blas={.a={0,}}}, 0)
, ccv_nnc_no_hint, 0, 0, 0, &copy, 1, 0);
2235 }
2236 }
2237 ccv_nnc_graph_set_default_static_schedule(compiled_data->apply_gradients.graph, compiled_data->stream_type, model->max_stream_count);
2238}
2239
2240void ccv_cnnp_model_apply_gradients(ccv_cnnp_model_t* const model, ccv_nnc_stream_context_t* const stream_context)
2241{
2242 ccv_cnnp_compiled_data_t* const compiled_data = model->compiled_data;
2243 assert(compiled_data)((void) sizeof ((compiled_data) ? 1 : 0), __extension__ ({ if
(compiled_data) ; else __assert_fail ("compiled_data", "ccv_cnnp_model.c"
, 2243, __extension__ __PRETTY_FUNCTION__); }))
;
2244 assert(compiled_data->graph_mode == CCV_CNNP_MODEL_GRAPH_MULTISTAGE_MODE)((void) sizeof ((compiled_data->graph_mode == CCV_CNNP_MODEL_GRAPH_MULTISTAGE_MODE
) ? 1 : 0), __extension__ ({ if (compiled_data->graph_mode
== CCV_CNNP_MODEL_GRAPH_MULTISTAGE_MODE) ; else __assert_fail
("compiled_data->graph_mode == CCV_CNNP_MODEL_GRAPH_MULTISTAGE_MODE"
, "ccv_cnnp_model.c", 2244, __extension__ __PRETTY_FUNCTION__
); }))
;
2245 const int parallel_count = ccv_max(model->parallel_count, 1)({ typeof (model->parallel_count) _a = (model->parallel_count
); typeof (1) _b = (1); (_a > _b) ? _a : _b; })
;
2246 assert(model->graph)((void) sizeof ((model->graph) ? 1 : 0), __extension__ ({ if
(model->graph) ; else __assert_fail ("model->graph", "ccv_cnnp_model.c"
, 2246, __extension__ __PRETTY_FUNCTION__); }))
;
2247 assert(compiled_data->graph)((void) sizeof ((compiled_data->graph) ? 1 : 0), __extension__
({ if (compiled_data->graph) ; else __assert_fail ("compiled_data->graph"
, "ccv_cnnp_model.c", 2247, __extension__ __PRETTY_FUNCTION__
); }))
;
2248 // Skip if there is no backward pass.
2249 if (compiled_data->backward.count <= 0)
2250 return;
2251 // Skip if there is no parameters.
2252 if (compiled_data->parameters->rnum == 0)
2253 {
2254 compiled_data->backward.count = 0;
2255 return;
2256 }
2257 if (!compiled_data->apply_gradients.graph)
2258 _ccv_cnnp_model_multistage_jit_2(model);
2259 else {
2260 const int parameter_size = compiled_data->parameters->rnum;
2261 ccv_nnc_tensor_arena_clear_bindings(compiled_data->apply_gradients.tensor_arena);
2262 // Change to bind accum_gradients if we do gradient accumulation (run backward more than once).
2263 if (compiled_data->backward.count > 1)
2264 _ccv_cnnp_bind_tensors_to_arena(compiled_data->apply_gradients.tensor_arena, model->graph, compiled_data->gradients, compiled_data->tensors.accum_gradients, parameter_size, parallel_count);
2265 else
2266 _ccv_cnnp_bind_tensors_to_arena(compiled_data->apply_gradients.tensor_arena, model->graph, compiled_data->gradients, compiled_data->tensors.gradients, parameter_size, parallel_count);
2267 }
2268 if (compiled_data->apply_gradients.graph)
2269 ccv_nnc_graph_run_with_schedule(compiled_data->apply_gradients.graph, 0, 0, 0, stream_context);
2270 // Reset backward count to 0.
2271 compiled_data->backward.count = 0;
2272}
2273
2274void ccv_cnnp_model_set_parameter(ccv_cnnp_model_t* const model, const ccv_cnnp_model_io_t parameter, const ccv_nnc_tensor_t* const tensor)
2275{
2276 ccv_cnnp_compiled_data_t* const compiled_data = model->compiled_data;
2277 const int param_sel = parameter->param_sel > 0 ? parameter->param_sel - 1 : parameter->param_sel;
2278 assert(parameter->param_sel != 0)((void) sizeof ((parameter->param_sel != 0) ? 1 : 0), __extension__
({ if (parameter->param_sel != 0) ; else __assert_fail ("parameter->param_sel != 0"
, "ccv_cnnp_model.c", 2278, __extension__ __PRETTY_FUNCTION__
); }))
;
2279 const int tensors_init = !!compiled_data->tensors_init.v;
2280 int this_tensor_init = tensors_init;
2281 if (!tensors_init)
2282 ccv_cnnp_model_tensors_init_0(model, compiled_data);
2283 else if ((uintptr_t)compiled_data->tensors_init.v & (uintptr_t)1)
2284 // Check if it is not fully allocated, if it is not, init_1.
2285 this_tensor_init = 0;
2286 ccv_array_t* const parameter_indices = ccv_array_new(sizeof(int), 0, 0);
2287 ccv_cnnp_model_add_to_parameter_indices(parameter->model, param_sel, parameter_indices);
2288 const int param_ref = parameter->param_ref > 0 ? parameter->param_ref - 1 : parameter->param_ref;
2289 if (param_ref < 0)
2290 { assert(parameter_indices->rnum == 1)((void) sizeof ((parameter_indices->rnum == 1) ? 1 : 0), __extension__
({ if (parameter_indices->rnum == 1) ; else __assert_fail
("parameter_indices->rnum == 1", "ccv_cnnp_model.c", 2290
, __extension__ __PRETTY_FUNCTION__); }))
; }
2291 else
2292 { assert(param_ref < parameter_indices->rnum)((void) sizeof ((param_ref < parameter_indices->rnum) ?
1 : 0), __extension__ ({ if (param_ref < parameter_indices
->rnum) ; else __assert_fail ("param_ref < parameter_indices->rnum"
, "ccv_cnnp_model.c", 2292, __extension__ __PRETTY_FUNCTION__
); }))
; }
2293 const int d = *(int*)ccv_array_get(parameter_indices, param_ref >= 0 ? param_ref : 0)((void*)(((char*)((parameter_indices)->data)) + (size_t)(parameter_indices
)->rsize * (size_t)(param_ref >= 0 ? param_ref : 0)))
;
2294 ccv_array_free(parameter_indices);
2295 const int parameter_size = compiled_data->parameters->rnum;
2296 assert(d >= 0)((void) sizeof ((d >= 0) ? 1 : 0), __extension__ ({ if (d >=
0) ; else __assert_fail ("d >= 0", "ccv_cnnp_model.c", 2296
, __extension__ __PRETTY_FUNCTION__); }))
;
2297 assert(d < parameter_size)((void) sizeof ((d < parameter_size) ? 1 : 0), __extension__
({ if (d < parameter_size) ; else __assert_fail ("d < parameter_size"
, "ccv_cnnp_model.c", 2297, __extension__ __PRETTY_FUNCTION__
); }))
;
2298 const int parallel_count = _ccv_cnnp_compiled_data_parallel_count(model, compiled_data);
2299 int i;
2300 if (!this_tensor_init)
2301 {
2302 if (compiled_data->tensors.parameters[d])
2303 {
2304 for (i = 1; i < parallel_count; i++)
2305 { assert(compiled_data->tensors.parameters[d + i * parameter_size])((void) sizeof ((compiled_data->tensors.parameters[d + i *
parameter_size]) ? 1 : 0), __extension__ ({ if (compiled_data
->tensors.parameters[d + i * parameter_size]) ; else __assert_fail
("compiled_data->tensors.parameters[d + i * parameter_size]"
, "ccv_cnnp_model.c", 2305, __extension__ __PRETTY_FUNCTION__
); }))
; }
2306 this_tensor_init = 1;
2307 } else {
2308 const ccv_nnc_tensor_symbol_t parameter = *(ccv_nnc_tensor_symbol_t*)ccv_array_get(compiled_data->parameters, d)((void*)(((char*)((compiled_data->parameters)->data)) +
(size_t)(compiled_data->parameters)->rsize * (size_t)(
d)))
;
2309 ccv_nnc_tensor_param_t info = ccv_nnc_tensor_symbol_params(parameter.graph, parameter);
2310 if (CCV_TENSOR_GET_DEVICE(info.type)((info.type) & 0xfff00) == CCV_COMPUTE_DEVICE_ANY)
2311 CCV_TENSOR_SET_DEVICE_ID(info.type, 0)(info.type) = (((info.type) & ~0xfff00) | (((0) & 0xfff
) << 8))
;
2312 const int device_id = CCV_TENSOR_GET_DEVICE_ID(info.type)(((info.type) & 0xfff00) >> 8);
2313 compiled_data->tensors.parameters[d] = ccv_nnc_tensor_new(0, info, 0);
2314 for (i = 1; i < parallel_count; i++)
2315 {
2316 if (i != device_id)
2317 CCV_TENSOR_SET_DEVICE_ID(info.type, i)(info.type) = (((info.type) & ~0xfff00) | (((i) & 0xfff
) << 8))
;
2318 else
2319 CCV_TENSOR_SET_DEVICE_ID(info.type, 0)(info.type) = (((info.type) & ~0xfff00) | (((0) & 0xfff
) << 8))
;
2320 compiled_data->tensors.parameters[d + i * parameter_size] = ccv_nnc_tensor_new(0, info, 0);
2321 }
2322 }
2323 }
2324 ccv_nnc_tensor_t* const dest = CCV_NNC_TENSOR(compiled_data->tensors.parameters[d])((ccv_nnc_tensor_t*)((uintptr_t)(compiled_data->tensors.parameters
[d]) & ~(uintptr_t)1))
;
2325 assert(dest)((void) sizeof ((dest) ? 1 : 0), __extension__ ({ if (dest) ;
else __assert_fail ("dest", "ccv_cnnp_model.c", 2325, __extension__
__PRETTY_FUNCTION__); }))
;
2326 ccv_nnc_cmd_exec(CMD_DATA_TRANSFER_FORWARD()ccv_nnc_cmd(CCV_NNC_DATA_TRANSFER_FORWARD, 0, ccv_nnc_cmd_auto
, 0)
, ccv_nnc_no_hint, 0, TENSOR_LIST((ccv_nnc_tensor_t*)tensor)(ccv_nnc_tensor_t* []){(ccv_nnc_tensor_t*)tensor}, (1 +1 +0 +
0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0
+0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +
0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 -1
)
, TENSOR_LIST(dest)(ccv_nnc_tensor_t* []){dest}, (1 +1 +0 +0 +0 +0 +0 +0 +0 +0 +
0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0
+0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +
0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 -1)
, 0);
2327 for (i = 1; i < parallel_count; i++)
2328 {
2329 ccv_nnc_tensor_t* const copy_tensor = CCV_NNC_TENSOR(compiled_data->tensors.parameters[d + i * parameter_size])((ccv_nnc_tensor_t*)((uintptr_t)(compiled_data->tensors.parameters
[d + i * parameter_size]) & ~(uintptr_t)1))
;
2330 if (copy_tensor)
2331 ccv_nnc_cmd_exec(CMD_DATA_TRANSFER_FORWARD()ccv_nnc_cmd(CCV_NNC_DATA_TRANSFER_FORWARD, 0, ccv_nnc_cmd_auto
, 0)
, ccv_nnc_no_hint, 0, TENSOR_LIST(dest)(ccv_nnc_tensor_t* []){dest}, (1 +1 +0 +0 +0 +0 +0 +0 +0 +0 +
0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0
+0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +
0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 -1)
, TENSOR_LIST(copy_tensor)(ccv_nnc_tensor_t* []){copy_tensor}, (1 +1 +0 +0 +0 +0 +0 +0 +
0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0
+0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +
0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 -1)
, 0);
2332 }
2333 // Mark this symbol as init'ed.
2334 const int s = ((ccv_nnc_tensor_symbol_t*)ccv_array_get(compiled_data->parameters, d)((void*)(((char*)((compiled_data->parameters)->data)) +
(size_t)(compiled_data->parameters)->rsize * (size_t)(
d)))
)->d;
2335 uint32_t* const init_v = CCV_NNC_INIT_V(compiled_data->tensors_init.v)((uint32_t*)((uintptr_t)(compiled_data->tensors_init.v) &
~(uintptr_t)1))
;
2336 init_v[s >> 5] |= (1u << (s & 0x1f));
2337 // If we just allocated this tensor, now it is time to check if we need to mark it as fully allocated.
2338 if (!this_tensor_init)
2339 {
2340 if (ccv_cnnp_model_tensors_any_to_alloc(model, compiled_data))
2341 compiled_data->tensors_init.v = (uint32_t*)((uintptr_t)compiled_data->tensors_init.v | (uintptr_t)1);
2342 else // Remove the flag.
2343 compiled_data->tensors_init.v = CCV_NNC_INIT_V(compiled_data->tensors_init.v)((uint32_t*)((uintptr_t)(compiled_data->tensors_init.v) &
~(uintptr_t)1))
;
2344 }
2345}
2346
2347void ccv_cnnp_model_parameter_copy(ccv_cnnp_model_t* const model, const ccv_cnnp_model_io_t parameter, ccv_nnc_tensor_t* const tensor)
2348{
2349 ccv_cnnp_compiled_data_t* const compiled_data = model->compiled_data;
2350 const int param_sel = parameter->param_sel > 0 ? parameter->param_sel - 1 : parameter->param_sel;
2351 assert(parameter->param_sel != 0)((void) sizeof ((parameter->param_sel != 0) ? 1 : 0), __extension__
({ if (parameter->param_sel != 0) ; else __assert_fail ("parameter->param_sel != 0"
, "ccv_cnnp_model.c", 2351, __extension__ __PRETTY_FUNCTION__
); }))
;
2352 assert(compiled_data->tensors.parameters)((void) sizeof ((compiled_data->tensors.parameters) ? 1 : 0
), __extension__ ({ if (compiled_data->tensors.parameters)
; else __assert_fail ("compiled_data->tensors.parameters"
, "ccv_cnnp_model.c", 2352, __extension__ __PRETTY_FUNCTION__
); }))
;
2353 ccv_array_t* const parameter_indices = ccv_array_new(sizeof(int), 0, 0);
2354 ccv_cnnp_model_add_to_parameter_indices(parameter->model, param_sel, parameter_indices);
2355 const int param_ref = parameter->param_ref > 0 ? parameter->param_ref - 1 : parameter->param_ref;
2356 if (param_ref < 0)
2357 { assert(parameter_indices->rnum == 1)((void) sizeof ((parameter_indices->rnum == 1) ? 1 : 0), __extension__
({ if (parameter_indices->rnum == 1) ; else __assert_fail
("parameter_indices->rnum == 1", "ccv_cnnp_model.c", 2357
, __extension__ __PRETTY_FUNCTION__); }))
; }
2358 else
2359 { assert(param_ref < parameter_indices->rnum)((void) sizeof ((param_ref < parameter_indices->rnum) ?
1 : 0), __extension__ ({ if (param_ref < parameter_indices
->rnum) ; else __assert_fail ("param_ref < parameter_indices->rnum"
, "ccv_cnnp_model.c", 2359, __extension__ __PRETTY_FUNCTION__
); }))
; }
2360 const int d = *(int*)ccv_array_get(parameter_indices, param_ref >= 0 ? param_ref : 0)((void*)(((char*)((parameter_indices)->data)) + (size_t)(parameter_indices
)->rsize * (size_t)(param_ref >= 0 ? param_ref : 0)))
;
2361 ccv_array_free(parameter_indices);
2362 const int parameter_size = compiled_data->parameters->rnum;
2363 assert(d >= 0)((void) sizeof ((d >= 0) ? 1 : 0), __extension__ ({ if (d >=
0) ; else __assert_fail ("d >= 0", "ccv_cnnp_model.c", 2363
, __extension__ __PRETTY_FUNCTION__); }))
;
2364 assert(d < parameter_size)((void) sizeof ((d < parameter_size) ? 1 : 0), __extension__
({ if (d < parameter_size) ; else __assert_fail ("d < parameter_size"
, "ccv_cnnp_model.c", 2364, __extension__ __PRETTY_FUNCTION__
); }))
;
2365 // We don't need to consider parallel_count, every parameter on each device is identical.
2366 ccv_nnc_tensor_t* const src = CCV_NNC_TENSOR(compiled_data->tensors.parameters[d])((ccv_nnc_tensor_t*)((uintptr_t)(compiled_data->tensors.parameters
[d]) & ~(uintptr_t)1))
;
2367 assert(src)((void) sizeof ((src) ? 1 : 0), __extension__ ({ if (src) ; else
__assert_fail ("src", "ccv_cnnp_model.c", 2367, __extension__
__PRETTY_FUNCTION__); }))
;
2368 ccv_nnc_cmd_exec(CMD_DATA_TRANSFER_FORWARD()ccv_nnc_cmd(CCV_NNC_DATA_TRANSFER_FORWARD, 0, ccv_nnc_cmd_auto
, 0)
, ccv_nnc_no_hint, 0, TENSOR_LIST(src)(ccv_nnc_tensor_t* []){src}, (1 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0
+0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +
0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0
+0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 -1)
, TENSOR_LIST(tensor)(ccv_nnc_tensor_t* []){tensor}, (1 +1 +0 +0 +0 +0 +0 +0 +0 +0
+0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +
0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0
+0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 -1)
, 0);
2369}
2370
2371ccv_nnc_tensor_param_t ccv_cnnp_model_parameter_tensor_params(ccv_cnnp_model_t* const model, const ccv_cnnp_model_io_t parameter)
2372{
2373 ccv_cnnp_compiled_data_t* const compiled_data = model->compiled_data;
2374 const int param_sel = parameter->param_sel > 0 ? parameter->param_sel - 1 : parameter->param_sel;
2375 assert(parameter->param_sel != 0)((void) sizeof ((parameter->param_sel != 0) ? 1 : 0), __extension__
({ if (parameter->param_sel != 0) ; else __assert_fail ("parameter->param_sel != 0"
, "ccv_cnnp_model.c", 2375, __extension__ __PRETTY_FUNCTION__
); }))
;
2376 assert(compiled_data->tensors.parameters)((void) sizeof ((compiled_data->tensors.parameters) ? 1 : 0
), __extension__ ({ if (compiled_data->tensors.parameters)
; else __assert_fail ("compiled_data->tensors.parameters"
, "ccv_cnnp_model.c", 2376, __extension__ __PRETTY_FUNCTION__
); }))
;
2377 ccv_array_t* const parameter_indices = ccv_array_new(sizeof(int), 0, 0);
2378 ccv_cnnp_model_add_to_parameter_indices(parameter->model, param_sel, parameter_indices);
2379 const int param_ref = parameter->param_ref > 0 ? parameter->param_ref - 1 : parameter->param_ref;
2380 if (param_ref < 0)
2381 { assert(parameter_indices->rnum == 1)((void) sizeof ((parameter_indices->rnum == 1) ? 1 : 0), __extension__
({ if (parameter_indices->rnum == 1) ; else __assert_fail
("parameter_indices->rnum == 1", "ccv_cnnp_model.c", 2381
, __extension__ __PRETTY_FUNCTION__); }))
; }
2382 else
2383 { assert(param_ref < parameter_indices->rnum)((void) sizeof ((param_ref < parameter_indices->rnum) ?
1 : 0), __extension__ ({ if (param_ref < parameter_indices
->rnum) ; else __assert_fail ("param_ref < parameter_indices->rnum"
, "ccv_cnnp_model.c", 2383, __extension__ __PRETTY_FUNCTION__
); }))
; }
2384 const int d = *(int*)ccv_array_get(parameter_indices, param_ref >= 0 ? param_ref : 0)((void*)(((char*)((parameter_indices)->data)) + (size_t)(parameter_indices
)->rsize * (size_t)(param_ref >= 0 ? param_ref : 0)))
;
2385 ccv_array_free(parameter_indices);
2386 const int parameter_size = compiled_data->parameters->rnum;
2387 assert(d >= 0)((void) sizeof ((d >= 0) ? 1 : 0), __extension__ ({ if (d >=
0) ; else __assert_fail ("d >= 0", "ccv_cnnp_model.c", 2387
, __extension__ __PRETTY_FUNCTION__); }))
;
2388 assert(d < parameter_size)((void) sizeof ((d < parameter_size) ? 1 : 0), __extension__
({ if (d < parameter_size) ; else __assert_fail ("d < parameter_size"
, "ccv_cnnp_model.c", 2388, __extension__ __PRETTY_FUNCTION__
); }))
;
2389 // We don't need to consider parallel_count, every parameter on each device is identical.
2390 ccv_nnc_tensor_t* const tensor = CCV_NNC_TENSOR(compiled_data->tensors.parameters[d])((ccv_nnc_tensor_t*)((uintptr_t)(compiled_data->tensors.parameters
[d]) & ~(uintptr_t)1))
;
2391 assert(tensor)((void) sizeof ((tensor) ? 1 : 0), __extension__ ({ if (tensor
) ; else __assert_fail ("tensor", "ccv_cnnp_model.c", 2391, __extension__
__PRETTY_FUNCTION__); }))
;
2392 return tensor->info;
2393}
2394
2395const char* ccv_cnnp_model_parameter_name(ccv_cnnp_model_t* const model, const ccv_cnnp_model_io_t parameter)
2396{
2397 ccv_cnnp_compiled_data_t* const compiled_data = model->compiled_data;
2398 const int param_sel = parameter->param_sel > 0 ? parameter->param_sel - 1 : parameter->param_sel;
2399 assert(parameter->param_sel != 0)((void) sizeof ((parameter->param_sel != 0) ? 1 : 0), __extension__
({ if (parameter->param_sel != 0) ; else __assert_fail ("parameter->param_sel != 0"
, "ccv_cnnp_model.c", 2399, __extension__ __PRETTY_FUNCTION__
); }))
;
2400 ccv_array_t* const parameter_indices = ccv_array_new(sizeof(int), 0, 0);
2401 ccv_cnnp_model_add_to_parameter_indices(parameter->model, param_sel, parameter_indices);
2402 const int param_ref = parameter->param_ref > 0 ? parameter->param_ref - 1 : parameter->param_ref;
2403 if (param_ref < 0)
2404 { assert(parameter_indices->rnum == 1)((void) sizeof ((parameter_indices->rnum == 1) ? 1 : 0), __extension__
({ if (parameter_indices->rnum == 1) ; else __assert_fail
("parameter_indices->rnum == 1", "ccv_cnnp_model.c", 2404
, __extension__ __PRETTY_FUNCTION__); }))
; }
2405 else
2406 { assert(param_ref < parameter_indices->rnum)((void) sizeof ((param_ref < parameter_indices->rnum) ?
1 : 0), __extension__ ({ if (param_ref < parameter_indices
->rnum) ; else __assert_fail ("param_ref < parameter_indices->rnum"
, "ccv_cnnp_model.c", 2406, __extension__ __PRETTY_FUNCTION__
); }))
; }
2407 const int d = *(int*)ccv_array_get(parameter_indices, param_ref >= 0 ? param_ref : 0)((void*)(((char*)((parameter_indices)->data)) + (size_t)(parameter_indices
)->rsize * (size_t)(param_ref >= 0 ? param_ref : 0)))
;
2408 ccv_array_free(parameter_indices);
2409 const int parameter_size = compiled_data->parameters->rnum;
2410 assert(d >= 0)((void) sizeof ((d >= 0) ? 1 : 0), __extension__ ({ if (d >=
0) ; else __assert_fail ("d >= 0", "ccv_cnnp_model.c", 2410
, __extension__ __PRETTY_FUNCTION__); }))
;
2411 assert(d < parameter_size)((void) sizeof ((d < parameter_size) ? 1 : 0), __extension__
({ if (d < parameter_size) ; else __assert_fail ("d < parameter_size"
, "ccv_cnnp_model.c", 2411, __extension__ __PRETTY_FUNCTION__
); }))
;
2412 return *(char**)ccv_array_get(compiled_data->ids.parameters, d)((void*)(((char*)((compiled_data->ids.parameters)->data
)) + (size_t)(compiled_data->ids.parameters)->rsize * (
size_t)(d)))
;
2413}
2414
2415int ccv_cnnp_model_parameter_count(ccv_cnnp_model_t* const model)
2416{
2417 assert(model->compiled_data)((void) sizeof ((model->compiled_data) ? 1 : 0), __extension__
({ if (model->compiled_data) ; else __assert_fail ("model->compiled_data"
, "ccv_cnnp_model.c", 2417, __extension__ __PRETTY_FUNCTION__
); }))
;
2418 ccv_cnnp_compiled_data_t* const compiled_data = model->compiled_data;
2419 return compiled_data->parameters->rnum;
2420}
2421
2422uint64_t ccv_cnnp_model_parameters_size(ccv_cnnp_model_t* const model)
2423{
2424 assert(model->compiled_data)((void) sizeof ((model->compiled_data) ? 1 : 0), __extension__
({ if (model->compiled_data) ; else __assert_fail ("model->compiled_data"
, "ccv_cnnp_model.c", 2424, __extension__ __PRETTY_FUNCTION__
); }))
;
2425 ccv_cnnp_compiled_data_t* const compiled_data = model->compiled_data;
2426 const int parameter_size = compiled_data->parameters->rnum;
2427 int i;
2428 const ccv_nnc_symbolic_graph_t* const graph = model->graph;
2429 uint64_t size = 0;
2430 const int tensors_init = !!compiled_data->tensors_init.v;
2431 uint32_t* const init_v = tensors_init ? CCV_NNC_INIT_V(compiled_data->tensors_init.v)((uint32_t*)((uintptr_t)(compiled_data->tensors_init.v) &
~(uintptr_t)1))
: 0;
2432 for (i = 0; i < parameter_size; i++)
2433 {
2434 const int d = ((ccv_nnc_tensor_symbol_t*)ccv_array_get(compiled_data->parameters, i)((void*)(((char*)((compiled_data->parameters)->data)) +
(size_t)(compiled_data->parameters)->rsize * (size_t)(
i)))
)->d;
2435 if (tensors_init && compiled_data->tensors.parameters && (init_v[d >> 5] | (1u << (d & 0x1f))) && compiled_data->tensors.parameters[i])
2436 {
2437 ccv_nnc_tensor_param_t params = compiled_data->tensors.parameters[i]->info;
2438 size += ccv_nnc_tensor_data_size(params);
2439 continue;
2440 }
2441 ccv_nnc_tensor_param_t params = ccv_nnc_tensor_symbol_params(graph, (ccv_nnc_tensor_symbol_t){
2442 .graph = graph,
2443 .d = d
2444 });
2445 size += ccv_nnc_tensor_data_size(params);
2446 }
2447 return size;
2448}
2449
2450int ccv_cnnp_model_parameters_move(ccv_cnnp_model_t* const model, char** const names, ccv_nnc_tensor_t** const tensors, const int count, int type)
2451{
2452 assert(model->compiled_data)((void) sizeof ((model->compiled_data) ? 1 : 0), __extension__
({ if (model->compiled_data) ; else __assert_fail ("model->compiled_data"
, "ccv_cnnp_model.c", 2452, __extension__ __PRETTY_FUNCTION__
); }))
;
2453 ccv_cnnp_compiled_data_t* const compiled_data = model->compiled_data;
2454 if (count != compiled_data->parameters->rnum)
2455 return 0;
2456 if (CCV_TENSOR_GET_DEVICE(type)((type) & 0xfff00) == CCV_COMPUTE_DEVICE_ANY)
2457 CCV_TENSOR_SET_DEVICE_ID(type, 0)(type) = (((type) & ~0xfff00) | (((0) & 0xfff) <<
8))
;
2458 int i;
2459 // We don't need to consider parallel_count, every parameter on each device is identical.
2460 for (i = 0; i < count; i++)
2461 {
2462 ccv_nnc_tensor_t* tensor = compiled_data->tensors.parameters[i];
2463 if ((uintptr_t)tensor & (uintptr_t)1) // If it is not owned. We don't do anything.
2464 {
2465 tensors[i] = 0;
2466 continue;
2467 }
2468 tensor = CCV_NNC_TENSOR(tensor)((ccv_nnc_tensor_t*)((uintptr_t)(tensor) & ~(uintptr_t)1)
)
;
2469 if (tensor->info.type == type)
2470 tensors[i] = tensor;
2471 else {
2472 ccv_nnc_tensor_param_t info = tensor->info;
2473 info.type = type;
2474 tensors[i] = ccv_nnc_tensor_new(0, info, 0); // Create this tensor, don't initiate copy yet.
2475 }
2476 }
2477 for (i = 0; i < count; i++)
2478 {
2479 ccv_nnc_tensor_t* tensor = compiled_data->tensors.parameters[i];
2480 if ((uintptr_t)tensor & (uintptr_t)1) // If it is not owned. We don't do anything.
2481 continue;
2482 tensor = CCV_NNC_TENSOR(tensor)((ccv_nnc_tensor_t*)((uintptr_t)(tensor) & ~(uintptr_t)1)
)
;
2483 // Now initiate transfer. We should do this one on a stream.
2484 if (tensor->info.type != type)
2485 ccv_nnc_cmd_exec(CMD_DATA_TRANSFER_FORWARD()ccv_nnc_cmd(CCV_NNC_DATA_TRANSFER_FORWARD, 0, ccv_nnc_cmd_auto
, 0)
, ccv_nnc_no_hint, 0, TENSOR_LIST(tensor)(ccv_nnc_tensor_t* []){tensor}, (1 +1 +0 +0 +0 +0 +0 +0 +0 +0
+0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +
0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0
+0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 -1)
, TENSOR_LIST(tensors[i])(ccv_nnc_tensor_t* []){tensors[i]}, (1 +1 +0 +0 +0 +0 +0 +0 +
0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0
+0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +
0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 -1)
, 0);
2486 }
2487 // Copy names and remove parameters.
2488 for (i = 0; i < count; i++)
2489 {
2490 ccv_nnc_tensor_t* const tensor = compiled_data->tensors.parameters[i];
2491 if ((uintptr_t)tensor & (uintptr_t)1) // If it is not owned. We don't do anything.
2492 {
2493 names[i] = 0;
2494 continue;
2495 }
2496 const char* const name = *(char**)ccv_array_get(compiled_data->ids.parameters, i)((void*)(((char*)((compiled_data->ids.parameters)->data
)) + (size_t)(compiled_data->ids.parameters)->rsize * (
size_t)(i)))
;
2497 const size_t name_len = ccv_min(strnlen(name, 1023), 1023)({ typeof (strnlen(name, 1023)) _a = (strnlen(name, 1023)); typeof
(1023) _b = (1023); (_a < _b) ? _a : _b; })
;
2498 names[i] = ccmallocmalloc(name_len + 1);
2499 names[i][name_len] = 0;
2500 memcpy(names[i], name, name_len);
2501 if (tensor->info.type == type)
2502 compiled_data->tensors.parameters[i] = 0; // Only move when it is moved.
2503 }
2504 return 1;
2505}
2506
2507KHASH_MAP_INIT_STR(ccv_cnnp_parameter_id, int)typedef struct kh_ccv_cnnp_parameter_id_s { khint_t n_buckets
, size, n_occupied, upper_bound; khint32_t *flags; kh_cstr_t *
keys; int *vals; } kh_ccv_cnnp_parameter_id_t; static inline __attribute__
((__unused__)) kh_ccv_cnnp_parameter_id_t *kh_init_ccv_cnnp_parameter_id
(void) { return (kh_ccv_cnnp_parameter_id_t*)calloc(1,sizeof(
kh_ccv_cnnp_parameter_id_t)); } static inline __attribute__ (
(__unused__)) void kh_destroy_ccv_cnnp_parameter_id(kh_ccv_cnnp_parameter_id_t
*h) { if (h) { free((void *)h->keys); free(h->flags); free
((void *)h->vals); free(h); } } static inline __attribute__
((__unused__)) void kh_clear_ccv_cnnp_parameter_id(kh_ccv_cnnp_parameter_id_t
*h) { if (h && h->flags) { memset(h->flags, 0xaa
, ((h->n_buckets) < 16? 1 : (h->n_buckets)>>4)
* sizeof(khint32_t)); h->size = h->n_occupied = 0; } }
static inline __attribute__ ((__unused__)) khint_t kh_get_ccv_cnnp_parameter_id
(const kh_ccv_cnnp_parameter_id_t *h, kh_cstr_t key) { if (h->
n_buckets) { khint_t k, i, last, mask, step = 0; mask = h->
n_buckets - 1; k = __ac_X31_hash_string(key); i = k & mask
; last = i; while (!((h->flags[i>>4]>>((i&
0xfU)<<1))&2) && (((h->flags[i>>4]
>>((i&0xfU)<<1))&1) || !(strcmp(h->keys
[i], key) == 0))) { i = (i + (++step)) & mask; if (i == last
) return h->n_buckets; } return ((h->flags[i>>4]>>
((i&0xfU)<<1))&3)? h->n_buckets : i; } else return
0; } static inline __attribute__ ((__unused__)) int kh_resize_ccv_cnnp_parameter_id
(kh_ccv_cnnp_parameter_id_t *h, khint_t new_n_buckets) { khint32_t
*new_flags = 0; khint_t j = 1; { (--(new_n_buckets), (new_n_buckets
)|=(new_n_buckets)>>1, (new_n_buckets)|=(new_n_buckets)
>>2, (new_n_buckets)|=(new_n_buckets)>>4, (new_n_buckets
)|=(new_n_buckets)>>8, (new_n_buckets)|=(new_n_buckets)
>>16, ++(new_n_buckets)); if (new_n_buckets < 4) new_n_buckets
= 4; if (h->size >= (khint_t)(new_n_buckets * __ac_HASH_UPPER
+ 0.5)) j = 0; else { new_flags = (khint32_t*)malloc(((new_n_buckets
) < 16? 1 : (new_n_buckets)>>4) * sizeof(khint32_t))
; if (!new_flags) return -1; memset(new_flags, 0xaa, ((new_n_buckets
) < 16? 1 : (new_n_buckets)>>4) * sizeof(khint32_t))
; if (h->n_buckets < new_n_buckets) { kh_cstr_t *new_keys
= (kh_cstr_t*)realloc((void *)h->keys,new_n_buckets * sizeof
(kh_cstr_t)); if (!new_keys) { free(new_flags); return -1; } h
->keys = new_keys; if (1) { int *new_vals = (int*)realloc(
(void *)h->vals,new_n_buckets * sizeof(int)); if (!new_vals
) { free(new_flags); return -1; } h->vals = new_vals; } } }
} if (j) { for (j = 0; j != h->n_buckets; ++j) { if (((h->
flags[j>>4]>>((j&0xfU)<<1))&3) == 0
) { kh_cstr_t key = h->keys[j]; int val; khint_t new_mask;
new_mask = new_n_buckets - 1; if (1) val = h->vals[j]; (h
->flags[j>>4]|=1ul<<((j&0xfU)<<1)); while
(1) { khint_t k, i, step = 0; k = __ac_X31_hash_string(key);
i = k & new_mask; while (!((new_flags[i>>4]>>
((i&0xfU)<<1))&2)) i = (i + (++step)) & new_mask
; (new_flags[i>>4]&=~(2ul<<((i&0xfU)<<
1))); if (i < h->n_buckets && ((h->flags[i>>
4]>>((i&0xfU)<<1))&3) == 0) { { kh_cstr_t
tmp = h->keys[i]; h->keys[i] = key; key = tmp; } if (1
) { int tmp = h->vals[i]; h->vals[i] = val; val = tmp; }
(h->flags[i>>4]|=1ul<<((i&0xfU)<<1)
); } else { h->keys[i] = key; if (1) h->vals[i] = val; break
; } } } } if (h->n_buckets > new_n_buckets) { h->keys
= (kh_cstr_t*)realloc((void *)h->keys,new_n_buckets * sizeof
(kh_cstr_t)); if (1) h->vals = (int*)realloc((void *)h->
vals,new_n_buckets * sizeof(int)); } free(h->flags); h->
flags = new_flags; h->n_buckets = new_n_buckets; h->n_occupied
= h->size; h->upper_bound = (khint_t)(h->n_buckets *
__ac_HASH_UPPER + 0.5); } return 0; } static inline __attribute__
((__unused__)) khint_t kh_put_ccv_cnnp_parameter_id(kh_ccv_cnnp_parameter_id_t
*h, kh_cstr_t key, int *ret) { khint_t x; if (h->n_occupied
>= h->upper_bound) { if (h->n_buckets > (h->size
<<1)) { if (kh_resize_ccv_cnnp_parameter_id(h, h->n_buckets
- 1) < 0) { *ret = -1; return h->n_buckets; } } else if
(kh_resize_ccv_cnnp_parameter_id(h, h->n_buckets + 1) <
0) { *ret = -1; return h->n_buckets; } } { khint_t k, i, site
, last, mask = h->n_buckets - 1, step = 0; x = site = h->
n_buckets; k = __ac_X31_hash_string(key); i = k & mask; if
(((h->flags[i>>4]>>((i&0xfU)<<1))&
2)) x = i; else { last = i; while (!((h->flags[i>>4]
>>((i&0xfU)<<1))&2) && (((h->flags
[i>>4]>>((i&0xfU)<<1))&1) || !(strcmp
(h->keys[i], key) == 0))) { if (((h->flags[i>>4]>>
((i&0xfU)<<1))&1)) site = i; i = (i + (++step))
& mask; if (i == last) { x = site; break; } } if (x == h
->n_buckets) { if (((h->flags[i>>4]>>((i&
0xfU)<<1))&2) && site != h->n_buckets) x
= site; else x = i; } } } if (((h->flags[x>>4]>>
((x&0xfU)<<1))&2)) { h->keys[x] = key; (h->
flags[x>>4]&=~(3ul<<((x&0xfU)<<1)))
; ++h->size; ++h->n_occupied; *ret = 1; } else if (((h->
flags[x>>4]>>((x&0xfU)<<1))&1)) { h
->keys[x] = key; (h->flags[x>>4]&=~(3ul<<
((x&0xfU)<<1))); ++h->size; *ret = 2; } else *ret
= 0; return x; } static inline __attribute__ ((__unused__)) void
kh_del_ccv_cnnp_parameter_id(kh_ccv_cnnp_parameter_id_t *h, khint_t
x) { if (x != h->n_buckets && !((h->flags[x>>
4]>>((x&0xfU)<<1))&3)) { (h->flags[x>>
4]|=1ul<<((x&0xfU)<<1)); --h->size; } }
27
Taking true branch
28
Taking false branch
29
Calling 'kh_resize_ccv_cnnp_parameter_id'
30
Taking true branch
31
Assuming the condition is false
32
Taking false branch
33
'?' condition is true
34
Assuming 'new_flags' is non-null
35
Taking false branch
36
'?' condition is true
37
Taking true branch
38
Storing uninitialized value
39
Assuming 'new_keys' is non-null
40
Taking false branch
41
Taking true branch
42
Assuming 'new_vals' is non-null
43
Taking false branch
44
Taking true branch
45
Loop condition is false. Execution continues on line 2507
46
Taking false branch
47
Returning from 'kh_resize_ccv_cnnp_parameter_id'
48
Taking false branch
49
Assuming the condition is true
50
Taking true branch
51
Taking true branch
57
Assuming field 'n_occupied' is >= field 'upper_bound'
58
Taking true branch
59
Taking true branch
60
Calling 'kh_resize_ccv_cnnp_parameter_id'
61
Taking false branch
62
Assuming the condition is false
63
Taking false branch
64
'?' condition is true
65
Assuming 'new_flags' is non-null
66
Taking false branch
67
'?' condition is true
68
Taking false branch
69
Taking true branch
70
Loop condition is true. Entering loop body
71
Assuming the condition is false
72
Taking false branch
73
The value 1 is assigned to 'j'
74
Loop condition is true. Entering loop body
75
Assuming the condition is true
76
Taking true branch
77
Assigned value is garbage or undefined
2508
2509void ccv_cnnp_model_set_parameters_from_key_values(ccv_cnnp_model_t* const model, char* const* const names, ccv_nnc_tensor_t** const tensors, const int count, const int invalidates)
2510{
2511 assert(model->compiled_data)((void) sizeof ((model->compiled_data) ? 1 : 0), __extension__
({ if (model->compiled_data) ; else __assert_fail ("model->compiled_data"
, "ccv_cnnp_model.c", 2511, __extension__ __PRETTY_FUNCTION__
); }))
;
2512 ccv_cnnp_compiled_data_t* const compiled_data = model->compiled_data;
2513 int i;
2514 khash_t(ccv_cnnp_parameter_id)kh_ccv_cnnp_parameter_id_t* id_map = 0;
2515 if (count != compiled_data->parameters->rnum)
2516 {
2517 id_map = kh_init(ccv_cnnp_parameter_id)kh_init_ccv_cnnp_parameter_id();
2518 // Build the map between name and the index.
2519 for (i = 0; i < count; i++)
2520 {
2521 int ret;
2522 const khiter_t k = kh_put(ccv_cnnp_parameter_id, id_map, names[i], &ret)kh_put_ccv_cnnp_parameter_id(id_map, names[i], &ret);
2523 assert(ret != 0)((void) sizeof ((ret != 0) ? 1 : 0), __extension__ ({ if (ret
!= 0) ; else __assert_fail ("ret != 0", "ccv_cnnp_model.c", 2523
, __extension__ __PRETTY_FUNCTION__); }))
;
2524 kh_val(id_map, k)((id_map)->vals[k]) = i;
2525 }
2526 }
2527 const int parameter_size = compiled_data->parameters->rnum;
2528 int* copy_back = 0;
2529 const int tensors_init = !!compiled_data->tensors_init.v;
2530 if (!tensors_init)
2531 ccv_cnnp_model_tensors_init_0(model, compiled_data);
2532 const int parallel_count = ccv_max(model->parallel_count, 1)({ typeof (model->parallel_count) _a = (model->parallel_count
); typeof (1) _b = (1); (_a > _b) ? _a : _b; })
;
2533 uint32_t* const init_v = CCV_NNC_INIT_V(compiled_data->tensors_init.v)((uint32_t*)((uintptr_t)(compiled_data->tensors_init.v) &
~(uintptr_t)1))
;
2534 for (i = 0; i < parameter_size; i++)
2535 {
2536 int j = i;
2537 const char* const name = *(char**)ccv_array_get(compiled_data->ids.parameters, i)((void*)(((char*)((compiled_data->ids.parameters)->data
)) + (size_t)(compiled_data->ids.parameters)->rsize * (
size_t)(i)))
;
2538 if (i >= 0 || strncmp(name, names[i], 1023) != 0)
2539 {
2540 // Build the map.
2541 if (id_map == 0)
2542 {
2543 id_map = kh_init(ccv_cnnp_parameter_id)kh_init_ccv_cnnp_parameter_id();
2544 for (j = 0; j < count; j++)
2545 {
2546 int ret;
2547 const khiter_t k = kh_put(ccv_cnnp_parameter_id, id_map, names[j], &ret)kh_put_ccv_cnnp_parameter_id(id_map, names[j], &ret);
2548 assert(ret != 0)((void) sizeof ((ret != 0) ? 1 : 0), __extension__ ({ if (ret
!= 0) ; else __assert_fail ("ret != 0", "ccv_cnnp_model.c", 2548
, __extension__ __PRETTY_FUNCTION__); }))
;
2549 kh_val(id_map, k)((id_map)->vals[k]) = j;
2550 }
2551 }
2552 const khiter_t k = kh_get(ccv_cnnp_parameter_id, id_map, name)kh_get_ccv_cnnp_parameter_id(id_map, name);
2553 if (k == kh_end(id_map)((id_map)->n_buckets)) // Cannot find the name, skip.
2554 continue;
2555 j = kh_val(id_map, k)((id_map)->vals[k]);
2556 }
2557 if (compiled_data->tensors.parameters[i]) // Cannot be a shared parameter to read.
2558 { assert(!((uintptr_t)compiled_data->tensors.parameters[i] & (uintptr_t)1))((void) sizeof ((!((uintptr_t)compiled_data->tensors.parameters
[i] & (uintptr_t)1)) ? 1 : 0), __extension__ ({ if (!((uintptr_t
)compiled_data->tensors.parameters[i] & (uintptr_t)1))
; else __assert_fail ("!((uintptr_t)compiled_data->tensors.parameters[i] & (uintptr_t)1)"
, "ccv_cnnp_model.c", 2558, __extension__ __PRETTY_FUNCTION__
); }))
; }
2559 const ccv_nnc_tensor_symbol_t parameter = *(ccv_nnc_tensor_symbol_t*)ccv_array_get(compiled_data->parameters, i)((void*)(((char*)((compiled_data->parameters)->data)) +
(size_t)(compiled_data->parameters)->rsize * (size_t)(
i)))
;
2560 ccv_nnc_tensor_param_t info = ccv_nnc_tensor_symbol_params(parameter.graph, parameter);
2561 if (CCV_TENSOR_GET_DEVICE(info.type)((info.type) & 0xfff00) == CCV_COMPUTE_DEVICE_ANY)
2562 CCV_TENSOR_SET_DEVICE_ID(info.type, 0)(info.type) = (((info.type) & ~0xfff00) | (((0) & 0xfff
) << 8))
;
2563 const int d = parameter.d;
2564 if (info.type == tensors[j]->info.type && invalidates) // Can move.
2565 {
2566 // Deallocate it if needed.
2567 if (!((uintptr_t)compiled_data->tensors.parameters[i] & (uintptr_t)1))
2568 if (compiled_data->tensors.parameters[i])
2569 ccv_nnc_tensor_free(compiled_data->tensors.parameters[i]);
2570 compiled_data->tensors.parameters[i] = tensors[j];
2571 tensors[j] = 0;
2572 } else {
2573 if (!compiled_data->tensors.parameters[i])
2574 { // Not allocated, to allocate first.
2575 // Create new one, make sure we create this by having the right parameters.
2576 const int type = info.type;
2577 info = tensors[j]->info;
2578 info.type = type; // Revert back the type.
2579 compiled_data->tensors.parameters[i] = ccv_nnc_tensor_new(0, info, 0);
2580 }
2581 if (!copy_back)
2582 copy_back = (int*)cccalloccalloc(parameter_size, sizeof(int));
2583 copy_back[i] = j + 1;
2584 }
2585 init_v[d >> 5] |= (1u << (d & 0x1f));
2586 // Create this tensor for other data parallel allocations.
2587 info = compiled_data->tensors.parameters[i]->info; // In case we loaded a different info.
2588 const int device_id = CCV_TENSOR_GET_DEVICE_ID(info.type)(((info.type) & 0xfff00) >> 8);
2589 for (j = 1; j < parallel_count; j++)
2590 if (!compiled_data->tensors.parameters[i + j * parameter_size])
2591 {
2592 if (j != device_id)
2593 CCV_TENSOR_SET_DEVICE_ID(info.type, j)(info.type) = (((info.type) & ~0xfff00) | (((j) & 0xfff
) << 8))
;
2594 else
2595 CCV_TENSOR_SET_DEVICE_ID(info.type, 0)(info.type) = (((info.type) & ~0xfff00) | (((0) & 0xfff
) << 8))
;
2596 compiled_data->tensors.parameters[i + j * parameter_size] = ccv_nnc_tensor_new(0, info, 0);
2597 }
2598 // No need to copy over, this is done in ccv_cnnp_model.c's copy_tensors method.
2599 }
2600 if (id_map)
2601 kh_destroy(ccv_cnnp_parameter_id, id_map)kh_destroy_ccv_cnnp_parameter_id(id_map);
2602 // Now do the transfer.
2603 if (copy_back)
2604 {
2605 for (i = 0; i < parameter_size; i++)
2606 {
2607 ccv_nnc_tensor_t* const tensor = CCV_NNC_TENSOR(compiled_data->tensors.parameters[i])((ccv_nnc_tensor_t*)((uintptr_t)(compiled_data->tensors.parameters
[i]) & ~(uintptr_t)1))
;
2608 if (copy_back[i] == 0)
2609 continue;
2610 const int j = copy_back[i] - 1;
2611 ccv_nnc_cmd_exec(CMD_DATA_TRANSFER_FORWARD()ccv_nnc_cmd(CCV_NNC_DATA_TRANSFER_FORWARD, 0, ccv_nnc_cmd_auto
, 0)
, ccv_nnc_no_hint, 0, TENSOR_LIST(tensors[j])(ccv_nnc_tensor_t* []){tensors[j]}, (1 +1 +0 +0 +0 +0 +0 +0 +
0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0
+0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +
0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 -1)
, TENSOR_LIST(tensor)(ccv_nnc_tensor_t* []){tensor}, (1 +1 +0 +0 +0 +0 +0 +0 +0 +0
+0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +
0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0
+0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 -1)
, 0);
2612 }
2613 ccfreefree(copy_back);
2614 }
2615}
2616
2617ccv_cnnp_model_io_t ccv_cnnp_model_parameter_first(ccv_cnnp_model_t* const model, ccv_cnnp_model_parameters_filter_f first, void* const context)
2618{
2619 ccv_cnnp_compiled_data_t* const compiled_data = model->compiled_data;
2620 assert(compiled_data)((void) sizeof ((compiled_data) ? 1 : 0), __extension__ ({ if
(compiled_data) ; else __assert_fail ("compiled_data", "ccv_cnnp_model.c"
, 2620, __extension__ __PRETTY_FUNCTION__); }))
;
2621 const int parameter_size = compiled_data->parameters->rnum;
2622 int i;
2623 for (i = 0; i < parameter_size; i++)
2624 {
2625 const char* const name = *(char**)ccv_array_get(compiled_data->ids.parameters, i)((void*)(((char*)((compiled_data->ids.parameters)->data
)) + (size_t)(compiled_data->ids.parameters)->rsize * (
size_t)(i)))
;
2626 if (first(model, name, context))
2627 return ccv_cnnp_model_parameters(model, -1, i);
2628 }
2629 return 0;
2630}
2631
2632ccv_array_t* ccv_cnnp_model_parameters_filter(ccv_cnnp_model_t* const model, ccv_cnnp_model_parameters_filter_f filter, void* const context)
2633{
2634 ccv_cnnp_compiled_data_t* const compiled_data = model->compiled_data;
2635 assert(compiled_data)((void) sizeof ((compiled_data) ? 1 : 0), __extension__ ({ if
(compiled_data) ; else __assert_fail ("compiled_data", "ccv_cnnp_model.c"
, 2635, __extension__ __PRETTY_FUNCTION__); }))
;
2636 ccv_array_t* const parameters = ccv_array_new(sizeof(ccv_cnnp_model_io_t), 0, 0);
2637 const int parameter_size = compiled_data->parameters->rnum;
2638 int i;
2639 for (i = 0; i < parameter_size; i++)
2640 {
2641 const char* const name = *(char**)ccv_array_get(compiled_data->ids.parameters, i)((void*)(((char*)((compiled_data->ids.parameters)->data
)) + (size_t)(compiled_data->ids.parameters)->rsize * (
size_t)(i)))
;
2642 if (filter(model, name, context))
2643 {
2644 ccv_cnnp_model_io_t parameter = ccv_cnnp_model_parameters(model, -1, i);
2645 ccv_array_push(parameters, &parameter);
2646 }
2647 }
2648 return parameters;
2649
2650}
2651
2652CCV_WARN_UNUSED(ccv_cnnp_model_io_t)ccv_cnnp_model_io_t __attribute__((warn_unused_result)) ccv_cnnp_model_parameter_first_uninit(ccv_cnnp_model_t* const model)
2653{
2654 ccv_cnnp_compiled_data_t* const compiled_data = model->compiled_data;
2655 assert(compiled_data)((void) sizeof ((compiled_data) ? 1 : 0), __extension__ ({ if
(compiled_data) ; else __assert_fail ("compiled_data", "ccv_cnnp_model.c"
, 2655, __extension__ __PRETTY_FUNCTION__); }))
;
2656 const int tensors_init = !!compiled_data->tensors_init.v;
2657 if (!tensors_init) // If nothing initialized, we return parameter 0.
2658 return ccv_cnnp_model_parameters(model, -1, 0);
2659 const int parameter_size = compiled_data->parameters->rnum;
2660 int i;
2661 const uint32_t* const init_v = CCV_NNC_INIT_V(compiled_data->tensors_init.v)((uint32_t*)((uintptr_t)(compiled_data->tensors_init.v) &
~(uintptr_t)1))
;
2662 for (i = 0; i < parameter_size; i++)
2663 {
2664 const int d = ((ccv_nnc_tensor_symbol_t*)ccv_array_get(compiled_data->parameters, i)((void*)(((char*)((compiled_data->parameters)->data)) +
(size_t)(compiled_data->parameters)->rsize * (size_t)(
i)))
)->d;
2665 if (!(init_v[d >> 5] & (1u << (d & 0x1f))))
2666 return ccv_cnnp_model_parameters(model, -1, i);
2667 }
2668 return 0;
2669}
2670
2671static ccv_array_t* _ccv_cnnp_model_parameter_indices(const ccv_cnnp_model_t* const model, const ccv_cnnp_model_io_t parameters, int* const param_ref)
2672{
2673 const int to_param_sel = parameters->param_sel > 0 ? parameters->param_sel - 1 : parameters->param_sel;
2674 assert(parameters->param_sel != 0)((void) sizeof ((parameters->param_sel != 0) ? 1 : 0), __extension__
({ if (parameters->param_sel != 0) ; else __assert_fail (
"parameters->param_sel != 0", "ccv_cnnp_model.c", 2674, __extension__
__PRETTY_FUNCTION__); }))
;
2675 ccv_array_t* const to_parameter_indices = ccv_array_new(sizeof(int), 0, 0);
2676 ccv_cnnp_model_add_to_parameter_indices(parameters->model, to_param_sel, to_parameter_indices);
2677 *param_ref = parameters->param_ref > 0 ? parameters->param_ref - 1 : parameters->param_ref;
2678 return to_parameter_indices;
2679}
2680
2681static void _ccv_cnnp_model_to_parameter_indices_and_from_parameter_indices(ccv_cnnp_model_t* const model, const ccv_cnnp_model_io_t parameters, const ccv_cnnp_model_t* const from_model, const ccv_cnnp_model_io_t from_parameters, ccv_array_t** const parameter_indices, int* const param_ref, ccv_array_t** const from_parameter_indices, int* const from_param_ref, const int only_init_0)
2682{
2683 // If the model is not compiled yet. Compile them now.
2684 if (!model->graph)
2685 {
2686 model->graph = ccv_nnc_symbolic_graph_new();
2687 assert(from_model->compiled_data)((void) sizeof ((from_model->compiled_data) ? 1 : 0), __extension__
({ if (from_model->compiled_data) ; else __assert_fail ("from_model->compiled_data"
, "ccv_cnnp_model.c", 2687, __extension__ __PRETTY_FUNCTION__
); }))
;
2688 const int input_size = from_model->input_size;
2689 ccv_nnc_tensor_param_t input_params[input_size];
2690 int i;
2691 for (i = 0; i < input_size; i++)
2692 input_params[i] = ccv_nnc_tensor_symbol_params(from_model->graph, from_model->inputs[i]);
2693 _ccv_cnnp_model_compile(model, input_params, input_size, from_model->compiled_data->loss);
2694 model->parallel_count = from_model->parallel_count;
2695 model->memory_compression = from_model->memory_compression;
2696 model->memory_reduction = from_model->memory_reduction;
2697 model->gradient_checkpointing = from_model->gradient_checkpointing;
2698 model->compiled_data->stream_type = from_model->compiled_data->stream_type;
2699 model->compiled_data->minimize.minimizer = from_model->compiled_data->minimize.minimizer;
2700 model->compiled_data->minimize.max_saved_aux_size = from_model->compiled_data->minimize.max_saved_aux_size;
2701 }
2702 ccv_cnnp_compiled_data_t* const to_compiled_data = model->compiled_data;
2703 assert(to_compiled_data)((void) sizeof ((to_compiled_data) ? 1 : 0), __extension__ ({
if (to_compiled_data) ; else __assert_fail ("to_compiled_data"
, "ccv_cnnp_model.c", 2703, __extension__ __PRETTY_FUNCTION__
); }))
;
2704 const int to_tensors_init = !!to_compiled_data->tensors_init.v;
2705 if (!to_tensors_init)
2706 {
2707 if (only_init_0)
2708 ccv_cnnp_model_tensors_init_0(model, to_compiled_data);
2709 else
2710 _ccv_cnnp_model_tensors_init(model, to_compiled_data);
2711 } else if (!only_init_0 && (uintptr_t)to_compiled_data->tensors_init.v & (uintptr_t)1)
2712 // Check if it is not fully allocated, if it is not, init_1.
2713 ccv_cnnp_model_tensors_init_1(model, to_compiled_data);
2714 assert(to_compiled_data->tensors.parameters)((void) sizeof ((to_compiled_data->tensors.parameters) ? 1
: 0), __extension__ ({ if (to_compiled_data->tensors.parameters
) ; else __assert_fail ("to_compiled_data->tensors.parameters"
, "ccv_cnnp_model.c", 2714, __extension__ __PRETTY_FUNCTION__
); }))
;
2715 *parameter_indices = _ccv_cnnp_model_parameter_indices(model, parameters, param_ref);
2716 *from_parameter_indices = _ccv_cnnp_model_parameter_indices(from_model, from_parameters, from_param_ref);
2717 if (*from_param_ref < 0 && *param_ref >= 0)
2718 { assert((*from_parameter_indices)->rnum == 1)((void) sizeof (((*from_parameter_indices)->rnum == 1) ? 1
: 0), __extension__ ({ if ((*from_parameter_indices)->rnum
== 1) ; else __assert_fail ("(*from_parameter_indices)->rnum == 1"
, "ccv_cnnp_model.c", 2718, __extension__ __PRETTY_FUNCTION__
); }))
; }
2719 else if (*from_param_ref >= 0)
2720 { assert(*from_param_ref < (*from_parameter_indices)->rnum)((void) sizeof ((*from_param_ref < (*from_parameter_indices
)->rnum) ? 1 : 0), __extension__ ({ if (*from_param_ref <
(*from_parameter_indices)->rnum) ; else __assert_fail ("*from_param_ref < (*from_parameter_indices)->rnum"
, "ccv_cnnp_model.c", 2720, __extension__ __PRETTY_FUNCTION__
); }))
; }
2721 if (*param_ref < 0 && *from_param_ref >= 0)
2722 { assert((*parameter_indices)->rnum == 1)((void) sizeof (((*parameter_indices)->rnum == 1) ? 1 : 0)
, __extension__ ({ if ((*parameter_indices)->rnum == 1) ; else
__assert_fail ("(*parameter_indices)->rnum == 1", "ccv_cnnp_model.c"
, 2722, __extension__ __PRETTY_FUNCTION__); }))
; }
2723 else if (*param_ref >= 0)
2724 { assert(*param_ref < (*parameter_indices)->rnum)((void) sizeof ((*param_ref < (*parameter_indices)->rnum
) ? 1 : 0), __extension__ ({ if (*param_ref < (*parameter_indices
)->rnum) ; else __assert_fail ("*param_ref < (*parameter_indices)->rnum"
, "ccv_cnnp_model.c", 2724, __extension__ __PRETTY_FUNCTION__
); }))
; }
2725}
2726
2727void ccv_cnnp_model_set_parameters(ccv_cnnp_model_t* const model, const ccv_cnnp_model_io_t parameters, const ccv_cnnp_model_t* const from_model, const ccv_cnnp_model_io_t from_parameters)
2728{
2729 ccv_array_t* to_parameter_indices;
2730 int to_param_ref;
2731 ccv_array_t* from_parameter_indices;
2732 int from_param_ref;
2733 _ccv_cnnp_model_to_parameter_indices_and_from_parameter_indices(model, parameters, from_model, from_parameters, &to_parameter_indices, &to_param_ref, &from_parameter_indices, &from_param_ref, 0);
2734 // Should be exactly the same tensor.
2735 if (to_param_ref < 0 && from_param_ref < 0)
2736 { assert(from_parameter_indices->rnum == to_parameter_indices->rnum)((void) sizeof ((from_parameter_indices->rnum == to_parameter_indices
->rnum) ? 1 : 0), __extension__ ({ if (from_parameter_indices
->rnum == to_parameter_indices->rnum) ; else __assert_fail
("from_parameter_indices->rnum == to_parameter_indices->rnum"
, "ccv_cnnp_model.c", 2736, __extension__ __PRETTY_FUNCTION__
); }))
; }
2737 // To models.
2738 ccv_cnnp_compiled_data_t* const to_compiled_data = model->compiled_data;
2739 assert(to_compiled_data)((void) sizeof ((to_compiled_data) ? 1 : 0), __extension__ ({
if (to_compiled_data) ; else __assert_fail ("to_compiled_data"
, "ccv_cnnp_model.c", 2739, __extension__ __PRETTY_FUNCTION__
); }))
;
2740 // From models.
2741 const ccv_cnnp_compiled_data_t* const from_compiled_data = from_model->compiled_data;
2742 const int parallel_count = ccv_max(model->parallel_count, 1)({ typeof (model->parallel_count) _a = (model->parallel_count
); typeof (1) _b = (1); (_a > _b) ? _a : _b; })
;
2743 const int to_parameter_size = to_compiled_data->parameters->rnum;
2744 const int rnum = (to_param_ref < 0 && from_param_ref < 0) ? from_parameter_indices->rnum : 1;
2745 int i, j;
2746 const uint32_t* const from_init_v = CCV_NNC_INIT_V(from_compiled_data->tensors_init.v)((uint32_t*)((uintptr_t)(from_compiled_data->tensors_init.
v) & ~(uintptr_t)1))
;
2747 uint32_t* const to_init_v = CCV_NNC_INIT_V(to_compiled_data->tensors_init.v)((uint32_t*)((uintptr_t)(to_compiled_data->tensors_init.v)
& ~(uintptr_t)1))
;
2748 for (i = 0; i < rnum; i++)
2749 {
2750 const int src_d = *(int*)ccv_array_get(from_parameter_indices,from_param_ref >= 0 ? from_param_ref : i)((void*)(((char*)((from_parameter_indices)->data)) + (size_t
)(from_parameter_indices)->rsize * (size_t)(from_param_ref
>= 0 ? from_param_ref : i)))
;
2751 assert(src_d >= 0)((void) sizeof ((src_d >= 0) ? 1 : 0), __extension__ ({ if
(src_d >= 0) ; else __assert_fail ("src_d >= 0", "ccv_cnnp_model.c"
, 2751, __extension__ __PRETTY_FUNCTION__); }))
;
2752 assert(src_d < from_compiled_data->parameters->rnum)((void) sizeof ((src_d < from_compiled_data->parameters
->rnum) ? 1 : 0), __extension__ ({ if (src_d < from_compiled_data
->parameters->rnum) ; else __assert_fail ("src_d < from_compiled_data->parameters->rnum"
, "ccv_cnnp_model.c", 2752, __extension__ __PRETTY_FUNCTION__
); }))
;
2753 const int s = ((ccv_nnc_tensor_symbol_t*)ccv_array_get(from_compiled_data->parameters, src_d)((void*)(((char*)((from_compiled_data->parameters)->data
)) + (size_t)(from_compiled_data->parameters)->rsize * (
size_t)(src_d)))
)->d;
2754 // If the original is not init'ed. We cannot copy from.
2755 if (!(from_init_v[s >> 5] & (1u << (s & 0x1f))))
2756 continue;
2757 const int dest_d = *(int*)ccv_array_get(to_parameter_indices, to_param_ref >= 0 ? to_param_ref : i)((void*)(((char*)((to_parameter_indices)->data)) + (size_t
)(to_parameter_indices)->rsize * (size_t)(to_param_ref >=
0 ? to_param_ref : i)))
;
2758 assert(dest_d >= 0)((void) sizeof ((dest_d >= 0) ? 1 : 0), __extension__ ({ if
(dest_d >= 0) ; else __assert_fail ("dest_d >= 0", "ccv_cnnp_model.c"
, 2758, __extension__ __PRETTY_FUNCTION__); }))
;
2759 assert(dest_d < to_compiled_data->parameters->rnum)((void) sizeof ((dest_d < to_compiled_data->parameters->
rnum) ? 1 : 0), __extension__ ({ if (dest_d < to_compiled_data
->parameters->rnum) ; else __assert_fail ("dest_d < to_compiled_data->parameters->rnum"
, "ccv_cnnp_model.c", 2759, __extension__ __PRETTY_FUNCTION__
); }))
;
2760 ccv_nnc_tensor_t* const src = CCV_NNC_TENSOR(from_compiled_data->tensors.parameters[src_d])((ccv_nnc_tensor_t*)((uintptr_t)(from_compiled_data->tensors
.parameters[src_d]) & ~(uintptr_t)1))
;
2761 assert(src)((void) sizeof ((src) ? 1 : 0), __extension__ ({ if (src) ; else
__assert_fail ("src", "ccv_cnnp_model.c", 2761, __extension__
__PRETTY_FUNCTION__); }))
;
2762 ccv_nnc_tensor_t* const dest = CCV_NNC_TENSOR(to_compiled_data->tensors.parameters[dest_d])((ccv_nnc_tensor_t*)((uintptr_t)(to_compiled_data->tensors
.parameters[dest_d]) & ~(uintptr_t)1))
;
2763 assert(dest)((void) sizeof ((dest) ? 1 : 0), __extension__ ({ if (dest) ;
else __assert_fail ("dest", "ccv_cnnp_model.c", 2763, __extension__
__PRETTY_FUNCTION__); }))
;
2764 ccv_nnc_cmd_exec(CMD_DATA_TRANSFER_FORWARD()ccv_nnc_cmd(CCV_NNC_DATA_TRANSFER_FORWARD, 0, ccv_nnc_cmd_auto
, 0)
, ccv_nnc_no_hint, 0, TENSOR_LIST(src)(ccv_nnc_tensor_t* []){src}, (1 +1 +0 +0 +0 +0 +0 +0 +0 +0 +0
+0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +
0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0
+0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 -1)
, TENSOR_LIST(dest)(ccv_nnc_tensor_t* []){dest}, (1 +1 +0 +0 +0 +0 +0 +0 +0 +0 +
0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0
+0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +
0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 -1)
, 0);
2765 for (j = 1; j < parallel_count; j++)
2766 {
2767 ccv_nnc_tensor_t* const copy_tensor = CCV_NNC_TENSOR(to_compiled_data->tensors.parameters[dest_d + j * to_parameter_size])((ccv_nnc_tensor_t*)((uintptr_t)(to_compiled_data->tensors
.parameters[dest_d + j * to_parameter_size]) & ~(uintptr_t
)1))
;
2768 if (copy_tensor)
2769 ccv_nnc_cmd_exec(CMD_DATA_TRANSFER_FORWARD()ccv_nnc_cmd(CCV_NNC_DATA_TRANSFER_FORWARD, 0, ccv_nnc_cmd_auto
, 0)
, ccv_nnc_no_hint, 0, TENSOR_LIST(dest)(ccv_nnc_tensor_t* []){dest}, (1 +1 +0 +0 +0 +0 +0 +0 +0 +0 +
0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0
+0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +
0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 -1)
, TENSOR_LIST(copy_tensor)(ccv_nnc_tensor_t* []){copy_tensor}, (1 +1 +0 +0 +0 +0 +0 +0 +
0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0
+0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +
0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 -1)
, 0);
2770 }
2771 // Mark this symbol as init'ed.
2772 const int d = ((ccv_nnc_tensor_symbol_t*)ccv_array_get(to_compiled_data->parameters, dest_d)((void*)(((char*)((to_compiled_data->parameters)->data)
) + (size_t)(to_compiled_data->parameters)->rsize * (size_t
)(dest_d)))
)->d;
2773 to_init_v[d >> 5] |= (1u << (d & 0x1f));
2774 }
2775 ccv_array_free(to_parameter_indices);
2776 ccv_array_free(from_parameter_indices);
2777}
2778
2779void ccv_cnnp_model_share_parameters(ccv_cnnp_model_t* const model, const ccv_cnnp_model_io_t parameters, const ccv_cnnp_model_t* const from_model, const ccv_cnnp_model_io_t from_parameters, ccv_cnnp_model_parameters_renamer_f renamer, void* const context)
2780{
2781 ccv_array_t* to_parameter_indices;
2782 int to_param_ref;
2783 ccv_array_t* from_parameter_indices;
2784 int from_param_ref;
2785 _ccv_cnnp_model_to_parameter_indices_and_from_parameter_indices(model, parameters, from_model, from_parameters, &to_parameter_indices, &to_param_ref, &from_parameter_indices, &from_param_ref, 1);
2786 // Should be exactly the same tensor.
2787 if (renamer == 0 && to_param_ref < 0 && from_param_ref < 0)
1
Assuming 'renamer' is not equal to null
2788 { assert(from_parameter_indices->rnum == to_parameter_indices->rnum)((void) sizeof ((from_parameter_indices->rnum == to_parameter_indices
->rnum) ? 1 : 0), __extension__ ({ if (from_parameter_indices
->rnum == to_parameter_indices->rnum) ; else __assert_fail
("from_parameter_indices->rnum == to_parameter_indices->rnum"
, "ccv_cnnp_model.c", 2788, __extension__ __PRETTY_FUNCTION__
); }))
; }
2789 // To models.
2790 ccv_cnnp_compiled_data_t* const to_compiled_data = model->compiled_data;
2791 assert(to_compiled_data)((void) sizeof ((to_compiled_data) ? 1 : 0), __extension__ ({
if (to_compiled_data) ; else __assert_fail ("to_compiled_data"
, "ccv_cnnp_model.c", 2791, __extension__ __PRETTY_FUNCTION__
); }))
;
2
Assuming 'to_compiled_data' is non-null
3
Taking true branch
2792 // From models.
2793 const ccv_cnnp_compiled_data_t* const from_compiled_data = from_model->compiled_data;
2794 const int parallel_count = ccv_max(model->parallel_count, 1)({ typeof (model->parallel_count) _a = (model->parallel_count
); typeof (1) _b = (1); (_a > _b) ? _a : _b; })
;
4
Assuming '_a' is <= '_b'
5
'?' condition is false
2795 assert(parallel_count == ccv_max(from_model->parallel_count, 1))((void) sizeof ((parallel_count == ({ typeof (from_model->
parallel_count) _a = (from_model->parallel_count); typeof (
1) _b = (1); (_a > _b) ? _a : _b; })) ? 1 : 0), __extension__
({ if (parallel_count == ({ typeof (from_model->parallel_count
) _a = (from_model->parallel_count); typeof (1) _b = (1); (
_a > _b) ? _a : _b; })) ; else __assert_fail ("parallel_count == ccv_max(from_model->parallel_count, 1)"
, "ccv_cnnp_model.c", 2795, __extension__ __PRETTY_FUNCTION__
); }))
; // Should have the same parallel count can share parameters.
6
Assuming '_a' is <= '_b'
7
'?' condition is false
8
Taking true branch
2796 const int from_parameter_size = from_compiled_data->parameters->rnum;
2797 const int to_parameter_size = to_compiled_data->parameters->rnum;
2798 const int rnum = (to_param_ref < 0 && from_param_ref < 0) ? to_parameter_indices->rnum : 1;
9
Assuming 'to_param_ref' is >= 0
2799 int i, j;
2800 khash_t(ccv_cnnp_parameter_id)kh_ccv_cnnp_parameter_id_t* id_map = 0;
2801 char* updated_name = 0;
2802 const uint32_t* const from_init_v = CCV_NNC_INIT_V(from_compiled_data->tensors_init.v)((uint32_t*)((uintptr_t)(from_compiled_data->tensors_init.
v) & ~(uintptr_t)1))
;
2803 uint32_t* const to_init_v = CCV_NNC_INIT_V(to_compiled_data->tensors_init.v)((uint32_t*)((uintptr_t)(to_compiled_data->tensors_init.v)
& ~(uintptr_t)1))
;
2804 for (i = 0; i < rnum; i++)
2805 {
2806 int src_d = (from_param_ref >= 0 ? from_param_ref : i) < from_parameter_indices->rnum ? *(int*)ccv_array_get(from_parameter_indices,from_param_ref >= 0 ? from_param_ref : i)((void*)(((char*)((from_parameter_indices)->data)) + (size_t
)(from_parameter_indices)->rsize * (size_t)(from_param_ref
>= 0 ? from_param_ref : i)))
: from_parameter_size;
10
Assuming 'from_param_ref' is < 0
11
'?' condition is false
12
Assuming the condition is false
13
'?' condition is false
2807 // Need to figure out how to use the renamer here.
2808 const int dest_d = *(int*)ccv_array_get(to_parameter_indices, to_param_ref >= 0 ? to_param_ref : i)((void*)(((char*)((to_parameter_indices)->data)) + (size_t
)(to_parameter_indices)->rsize * (size_t)(to_param_ref >=
0 ? to_param_ref : i)))
;
14
'?' condition is true
2809 assert(dest_d >= 0)((void) sizeof ((dest_d >= 0) ? 1 : 0), __extension__ ({ if
(dest_d >= 0) ; else __assert_fail ("dest_d >= 0", "ccv_cnnp_model.c"
, 2809, __extension__ __PRETTY_FUNCTION__); }))
;
15
Assuming 'dest_d' is >= 0
16
Taking true branch
2810 assert(dest_d < to_parameter_size)((void) sizeof ((dest_d < to_parameter_size) ? 1 : 0), __extension__
({ if (dest_d < to_parameter_size) ; else __assert_fail (
"dest_d < to_parameter_size", "ccv_cnnp_model.c", 2810, __extension__
__PRETTY_FUNCTION__); }))
;
17
Assuming 'dest_d' is < 'to_parameter_size'
18
Taking true branch
2811 if (renamer
18.1
'renamer' is non-null
)
2812 {
2813 const char* const src_name = (src_d
18.2
'src_d' is >= 'from_parameter_size'
< from_parameter_size && src_d >= 0) ? *(char**)ccv_array_get(from_compiled_data->ids.parameters, src_d)((void*)(((char*)((from_compiled_data->ids.parameters)->
data)) + (size_t)(from_compiled_data->ids.parameters)->
rsize * (size_t)(src_d)))
: 0;
2814 const char* const dest_name = *(char**)ccv_array_get(to_compiled_data->ids.parameters, dest_d)((void*)(((char*)((to_compiled_data->ids.parameters)->data
)) + (size_t)(to_compiled_data->ids.parameters)->rsize *
(size_t)(dest_d)))
;
2815 if (!updated_name
18.3
'updated_name' is null
)
19
Taking true branch
2816 updated_name = (char*)ccmallocmalloc(1024);
2817 const size_t src_name_len = src_name
19.1
'src_name' is equal to null
== 0 ? 0 : ccv_min(strnlen(src_name, 1023), 1023)({ typeof (strnlen(src_name, 1023)) _a = (strnlen(src_name, 1023
)); typeof (1023) _b = (1023); (_a < _b) ? _a : _b; })
;
20
'?' condition is true
2818 if (src_name_len
20.1
'src_name_len' is <= 0
> 0)
21
Taking false branch
2819 memcpy(updated_name, src_name, src_name_len);
2820 updated_name[src_name_len] = 0;
2821 if (renamer(context, dest_name, updated_name, 1024) != 0)
22
Assuming the condition is false
2822 continue; // Skip this.
2823 if (src_name
22.1
'src_name' is equal to null
!= 0 && memcmp(updated_name, src_name, src_name_len) == 0 && strnlen(updated_name, 1023) == src_name_len)
2824 {
2825 // Nothing changed.
2826 } else {
2827 if (!id_map
22.2
'id_map' is null
)
23
Taking true branch
2828 {
2829 id_map = kh_init(ccv_cnnp_parameter_id)kh_init_ccv_cnnp_parameter_id();
2830 for (j = 0; j < from_parameter_size; j++)
24
Assuming 'j' is < 'from_parameter_size'
25
Loop condition is true. Entering loop body
54
Assuming 'j' is < 'from_parameter_size'
55
Loop condition is true. Entering loop body
2831 {
2832 int ret;
2833 const khiter_t k = kh_put(ccv_cnnp_parameter_id, id_map, *(char**)ccv_array_get(from_compiled_data->ids.parameters, j), &ret)kh_put_ccv_cnnp_parameter_id(id_map, *(char**)((void*)(((char
*)((from_compiled_data->ids.parameters)->data)) + (size_t
)(from_compiled_data->ids.parameters)->rsize * (size_t)
(j))), &ret)
;
26
Calling 'kh_put_ccv_cnnp_parameter_id'
52
Returning from 'kh_put_ccv_cnnp_parameter_id'
56
Calling 'kh_put_ccv_cnnp_parameter_id'
2834 assert(ret != 0)((void) sizeof ((ret != 0) ? 1 : 0), __extension__ ({ if (ret
!= 0) ; else __assert_fail ("ret != 0", "ccv_cnnp_model.c", 2834
, __extension__ __PRETTY_FUNCTION__); }))
;
53
Taking true branch
2835 kh_val(id_map, k)((id_map)->vals[k]) = j;
2836 }
2837 }
2838 const khiter_t k = kh_get(ccv_cnnp_parameter_id, id_map, updated_name)kh_get_ccv_cnnp_parameter_id(id_map, updated_name);
2839 if (k == kh_end(id_map)((id_map)->n_buckets)) // Cannot find the name, skip.
2840 continue;
2841 src_d = kh_val(id_map, k)((id_map)->vals[k]);
2842 assert(src_d >= 0)((void) sizeof ((src_d >= 0) ? 1 : 0), __extension__ ({ if
(src_d >= 0) ; else __assert_fail ("src_d >= 0", "ccv_cnnp_model.c"
, 2842, __extension__ __PRETTY_FUNCTION__); }))
;
2843 assert(src_d < from_parameter_size)((void) sizeof ((src_d < from_parameter_size) ? 1 : 0), __extension__
({ if (src_d < from_parameter_size) ; else __assert_fail (
"src_d < from_parameter_size", "ccv_cnnp_model.c", 2843, __extension__
__PRETTY_FUNCTION__); }))
;
2844 }
2845 }
2846 assert(src_d >= 0)((void) sizeof ((src_d >= 0) ? 1 : 0), __extension__ ({ if
(src_d >= 0) ; else __assert_fail ("src_d >= 0", "ccv_cnnp_model.c"
, 2846, __extension__ __PRETTY_FUNCTION__); }))
;
2847 assert(src_d < from_parameter_size)((void) sizeof ((src_d < from_parameter_size) ? 1 : 0), __extension__
({ if (src_d < from_parameter_size) ; else __assert_fail (
"src_d < from_parameter_size", "ccv_cnnp_model.c", 2847, __extension__
__PRETTY_FUNCTION__); }))
;
2848 const int s = ((ccv_nnc_tensor_symbol_t*)ccv_array_get(from_compiled_data->parameters, src_d)((void*)(((char*)((from_compiled_data->parameters)->data
)) + (size_t)(from_compiled_data->parameters)->rsize * (
size_t)(src_d)))
)->d;
2849 // If the original is not init'ed. We cannot share from.
2850 if (!(from_init_v[s >> 5] & (1u << (s & 0x1f))))
2851 continue;
2852 for (j = 0; j < parallel_count; j++)
2853 {
2854 ccv_nnc_tensor_t* const src = CCV_NNC_TENSOR(from_compiled_data->tensors.parameters[src_d + j * from_parameter_size])((ccv_nnc_tensor_t*)((uintptr_t)(from_compiled_data->tensors
.parameters[src_d + j * from_parameter_size]) & ~(uintptr_t
)1))
;
2855 assert(src)((void) sizeof ((src) ? 1 : 0), __extension__ ({ if (src) ; else
__assert_fail ("src", "ccv_cnnp_model.c", 2855, __extension__
__PRETTY_FUNCTION__); }))
;
2856 ccv_nnc_tensor_t* const dest = to_compiled_data->tensors.parameters[dest_d + j * to_parameter_size];
2857 if (dest && !((uintptr_t)dest & (uintptr_t)1))
2858 ccv_nnc_tensor_free(dest);
2859 to_compiled_data->tensors.parameters[dest_d + j * to_parameter_size] = (ccv_nnc_tensor_t*)((uintptr_t)src | (uintptr_t)1);
2860 }
2861 // Mark this symbol as init'ed.
2862 const int d = ((ccv_nnc_tensor_symbol_t*)ccv_array_get(to_compiled_data->parameters, dest_d)((void*)(((char*)((to_compiled_data->parameters)->data)
) + (size_t)(to_compiled_data->parameters)->rsize * (size_t
)(dest_d)))
)->d;
2863 to_init_v[d >> 5] |= (1u << (d & 0x1f));
2864 }
2865 ccv_array_free(to_parameter_indices);
2866 ccv_array_free(from_parameter_indices);
2867 if (id_map)
2868 kh_destroy(ccv_cnnp_parameter_id, id_map)kh_destroy_ccv_cnnp_parameter_id(id_map);
2869 if (updated_name)
2870 ccfreefree(updated_name);
2871 // Mark it as incomplete so we will call init_1.
2872 if (ccv_cnnp_model_tensors_any_to_alloc(model, to_compiled_data))
2873 to_compiled_data->tensors_init.v = (uint32_t*)((uintptr_t)to_compiled_data->tensors_init.v | (uintptr_t)1);
2874 else // Remove the flag.
2875 to_compiled_data->tensors_init.v = CCV_NNC_INIT_V(to_compiled_data->tensors_init.v)((uint32_t*)((uintptr_t)(to_compiled_data->tensors_init.v)
& ~(uintptr_t)1))
;
2876}
2877
2878ccv_nnc_stream_context_t* ccv_cnnp_compiled_data_get_stream(ccv_cnnp_compiled_data_t* const compiled_data, const int type)
2879{
2880 if (!compiled_data->stream_map)
2881 compiled_data->stream_map = kh_init(stream_map)kh_init_stream_map();
2882 int ret = 0;
2883 khiter_t k = kh_put(stream_map, compiled_data->stream_map, type, &ret)kh_put_stream_map(compiled_data->stream_map, type, &ret
)
;
2884 assert(ret >= 0)((void) sizeof ((ret >= 0) ? 1 : 0), __extension__ ({ if (
ret >= 0) ; else __assert_fail ("ret >= 0", "ccv_cnnp_model.c"
, 2884, __extension__ __PRETTY_FUNCTION__); }))
;
2885 ccv_nnc_stream_context_t* stream = kh_val(compiled_data->stream_map, k)((compiled_data->stream_map)->vals[k]);
2886 // If ret == 0, the key already exist, we can return directly, otherwise, create and return.
2887 if (ret != 0)
2888 {
2889 stream = ccv_nnc_stream_context_new(type);
2890 kh_val(compiled_data->stream_map, k)((compiled_data->stream_map)->vals[k]) = stream;
2891 }
2892 return stream;
2893}
2894
2895void ccv_cnnp_model_parameters_zip_map(ccv_cnnp_model_t* const model, const ccv_cnnp_model_io_t parameters, const ccv_nnc_cmd_t cmd, const ccv_nnc_hint_t hint, const int flags, ccv_nnc_tensor_t* const* const aux_ins, const int aux_in_size, ccv_nnc_tensor_t* const* const aux_outs, const int aux_out_size, ccv_nnc_stream_context_t* const stream_context, const ccv_cnnp_model_t* const from_model, const ccv_cnnp_model_io_t from_parameters)
2896{
2897 ccv_array_t* to_parameter_indices;
2898 int to_param_ref;
2899 ccv_array_t* from_parameter_indices;
2900 int from_param_ref;
2901 _ccv_cnnp_model_to_parameter_indices_and_from_parameter_indices(model, parameters, from_model, from_parameters, &to_parameter_indices, &to_param_ref, &from_parameter_indices, &from_param_ref, 0);
2902 // Should be exactly the same tensor.
2903 if (to_param_ref < 0 && from_param_ref < 0)
2904 { assert(from_parameter_indices->rnum == to_parameter_indices->rnum)((void) sizeof ((from_parameter_indices->rnum == to_parameter_indices
->rnum) ? 1 : 0), __extension__ ({ if (from_parameter_indices
->rnum == to_parameter_indices->rnum) ; else __assert_fail
("from_parameter_indices->rnum == to_parameter_indices->rnum"
, "ccv_cnnp_model.c", 2904, __extension__ __PRETTY_FUNCTION__
); }))
; }
2905 // To models.
2906 ccv_cnnp_compiled_data_t* const to_compiled_data = model->compiled_data;
2907 assert(to_compiled_data)((void) sizeof ((to_compiled_data) ? 1 : 0), __extension__ ({
if (to_compiled_data) ; else __assert_fail ("to_compiled_data"
, "ccv_cnnp_model.c", 2907, __extension__ __PRETTY_FUNCTION__
); }))
;
2908 // From models.
2909 const ccv_cnnp_compiled_data_t* const from_compiled_data = from_model->compiled_data;
2910 const int parallel_count = ccv_max(model->parallel_count, 1)({ typeof (model->parallel_count) _a = (model->parallel_count
); typeof (1) _b = (1); (_a > _b) ? _a : _b; })
;
2911 const int to_parameter_size = to_compiled_data->parameters->rnum;
2912 const int rnum = (to_param_ref < 0 && from_param_ref < 0) ? from_parameter_indices->rnum : 1;
2913 assert(aux_in_size >= 0)((void) sizeof ((aux_in_size >= 0) ? 1 : 0), __extension__
({ if (aux_in_size >= 0) ; else __assert_fail ("aux_in_size >= 0"
, "ccv_cnnp_model.c", 2913, __extension__ __PRETTY_FUNCTION__
); }))
;
2914 assert(aux_out_size >= 0)((void) sizeof ((aux_out_size >= 0) ? 1 : 0), __extension__
({ if (aux_out_size >= 0) ; else __assert_fail ("aux_out_size >= 0"
, "ccv_cnnp_model.c", 2914, __extension__ __PRETTY_FUNCTION__
); }))
;
2915 int i, j;
2916 ccv_nnc_tensor_t* inputs[aux_in_size + 2];
2917 ccv_nnc_tensor_t* outputs[aux_out_size + 1];
2918 for (i = 0; i < aux_in_size; i++)
2919 inputs[i + 2] = aux_ins[i];
2920 for (i = 0; i < aux_out_size; i++)
2921 outputs[i + 1] = aux_outs[i];
2922 const uint32_t* const from_init_v = CCV_NNC_INIT_V(from_compiled_data->tensors_init.v)((uint32_t*)((uintptr_t)(from_compiled_data->tensors_init.
v) & ~(uintptr_t)1))
;
2923 uint32_t* const to_init_v = CCV_NNC_INIT_V(to_compiled_data->tensors_init.v)((uint32_t*)((uintptr_t)(to_compiled_data->tensors_init.v)
& ~(uintptr_t)1))
;
2924 for (i = 0; i < rnum; i++)
2925 {
2926 const int src_d = *(int*)ccv_array_get(from_parameter_indices,from_param_ref >= 0 ? from_param_ref : i)((void*)(((char*)((from_parameter_indices)->data)) + (size_t
)(from_parameter_indices)->rsize * (size_t)(from_param_ref
>= 0 ? from_param_ref : i)))
;
2927 assert(src_d >= 0)((void) sizeof ((src_d >= 0) ? 1 : 0), __extension__ ({ if
(src_d >= 0) ; else __assert_fail ("src_d >= 0", "ccv_cnnp_model.c"
, 2927, __extension__ __PRETTY_FUNCTION__); }))
;
2928 assert(src_d < from_compiled_data->parameters->rnum)((void) sizeof ((src_d < from_compiled_data->parameters
->rnum) ? 1 : 0), __extension__ ({ if (src_d < from_compiled_data
->parameters->rnum) ; else __assert_fail ("src_d < from_compiled_data->parameters->rnum"
, "ccv_cnnp_model.c", 2928, __extension__ __PRETTY_FUNCTION__
); }))
;
2929 const int s = ((ccv_nnc_tensor_symbol_t*)ccv_array_get(from_compiled_data->parameters, src_d)((void*)(((char*)((from_compiled_data->parameters)->data
)) + (size_t)(from_compiled_data->parameters)->rsize * (
size_t)(src_d)))
)->d;
2930 // If the original is not init'ed. We cannot copy from.
2931 if (!(from_init_v[s >> 5] & (1u << (s & 0x1f))))
2932 continue;
2933 const int dest_d = *(int*)ccv_array_get(to_parameter_indices, to_param_ref >= 0 ? to_param_ref : i)((void*)(((char*)((to_parameter_indices)->data)) + (size_t
)(to_parameter_indices)->rsize * (size_t)(to_param_ref >=
0 ? to_param_ref : i)))
;
2934 assert(dest_d >= 0)((void) sizeof ((dest_d >= 0) ? 1 : 0), __extension__ ({ if
(dest_d >= 0) ; else __assert_fail ("dest_d >= 0", "ccv_cnnp_model.c"
, 2934, __extension__ __PRETTY_FUNCTION__); }))
;
2935 assert(dest_d < to_compiled_data->parameters->rnum)((void) sizeof ((dest_d < to_compiled_data->parameters->
rnum) ? 1 : 0), __extension__ ({ if (dest_d < to_compiled_data
->parameters->rnum) ; else __assert_fail ("dest_d < to_compiled_data->parameters->rnum"
, "ccv_cnnp_model.c", 2935, __extension__ __PRETTY_FUNCTION__
); }))
;
2936 if (parallel_count > 1)
2937 {
2938 ccv_nnc_stream_context_t* streams[parallel_count];
2939 ccv_nnc_stream_signal_t* signal;
2940 if (stream_context)
2941 signal = ccv_nnc_stream_context_emit_signal_new(stream_context);
2942 for (j = 0; j < parallel_count; j++)
2943 {
2944 ccv_nnc_tensor_t* const src = CCV_NNC_TENSOR(from_compiled_data->tensors.parameters[src_d + j * to_parameter_size])((ccv_nnc_tensor_t*)((uintptr_t)(from_compiled_data->tensors
.parameters[src_d + j * to_parameter_size]) & ~(uintptr_t
)1))
;
2945 ccv_nnc_tensor_t* const dest = CCV_NNC_TENSOR(to_compiled_data->tensors.parameters[dest_d + j * to_parameter_size])((ccv_nnc_tensor_t*)((uintptr_t)(to_compiled_data->tensors
.parameters[dest_d + j * to_parameter_size]) & ~(uintptr_t
)1))
;
2946 if (!dest || !src)
2947 {
2948 streams[j] = 0;
2949 continue;
2950 }
2951 // At the moment, can only handle them on the same device.
2952 assert(CCV_TENSOR_GET_MEMORY(src->info.type) == CCV_TENSOR_GET_MEMORY(dest->info.type))((void) sizeof ((((src->info.type) & 0x3) == ((dest->
info.type) & 0x3)) ? 1 : 0), __extension__ ({ if (((src->
info.type) & 0x3) == ((dest->info.type) & 0x3)) ; else
__assert_fail ("CCV_TENSOR_GET_MEMORY(src->info.type) == CCV_TENSOR_GET_MEMORY(dest->info.type)"
, "ccv_cnnp_model.c", 2952, __extension__ __PRETTY_FUNCTION__
); }))
;
2953 assert(CCV_TENSOR_GET_DEVICE_ID(src->info.type) == CCV_TENSOR_GET_DEVICE_ID(dest->info.type))((void) sizeof (((((src->info.type) & 0xfff00) >>
8) == (((dest->info.type) & 0xfff00) >> 8)) ? 1
: 0), __extension__ ({ if ((((src->info.type) & 0xfff00
) >> 8) == (((dest->info.type) & 0xfff00) >>
8)) ; else __assert_fail ("CCV_TENSOR_GET_DEVICE_ID(src->info.type) == CCV_TENSOR_GET_DEVICE_ID(dest->info.type)"
, "ccv_cnnp_model.c", 2953, __extension__ __PRETTY_FUNCTION__
); }))
;
2954 const int stream_type = CCV_TENSOR_GET_MEMORY(src->info.type)((src->info.type) & 0x3) == CCV_TENSOR_GPU_MEMORY ? CCV_STREAM_CONTEXT_GPU : CCV_STREAM_CONTEXT_CPU;
2955 const int device_id = CCV_TENSOR_GET_DEVICE_ID(src->info.type)(((src->info.type) & 0xfff00) >> 8);
2956 int type = stream_type;
2957 CCV_STREAM_SET_DEVICE_ID(type, device_id)(type) = (((type) & ~0xfff00) | (((device_id) & 0xfff
) << 8))
;
2958 ccv_nnc_stream_context_t* const stream_0 = ccv_cnnp_compiled_data_get_stream(to_compiled_data, type);
2959 // Wait signal to finish.
2960 if (stream_context)
2961 ccv_nnc_stream_context_wait_signal(stream_0, signal);
2962 inputs[0] = outputs[0] = dest;
2963 inputs[1] = src;
2964 ccv_nnc_cmd_exec(cmd, hint, flags, inputs, aux_in_size + 2, outputs, aux_out_size + 1, stream_0);
2965 if (stream_context)
2966 {
2967 ccv_nnc_stream_signal_t* const signal = ccv_nnc_stream_context_emit_signal_new(stream_0);
2968 ccv_nnc_stream_context_wait_signal(stream_context, signal);
2969 }
2970 streams[j] = stream_0;
2971 }
2972 // If this should be blocking, blocking it.
2973 if (!stream_context)
2974 for (j = 0; j < parallel_count; j++)
2975 if (streams[j])
2976 ccv_nnc_stream_context_wait(streams[j]);
2977 } else {
2978 ccv_nnc_tensor_t* const src = CCV_NNC_TENSOR(from_compiled_data->tensors.parameters[src_d])((ccv_nnc_tensor_t*)((uintptr_t)(from_compiled_data->tensors
.parameters[src_d]) & ~(uintptr_t)1))
;
2979 assert(src)((void) sizeof ((src) ? 1 : 0), __extension__ ({ if (src) ; else
__assert_fail ("src", "ccv_cnnp_model.c", 2979, __extension__
__PRETTY_FUNCTION__); }))
;
2980 ccv_nnc_tensor_t* const dest = CCV_NNC_TENSOR(to_compiled_data->tensors.parameters[dest_d])((ccv_nnc_tensor_t*)((uintptr_t)(to_compiled_data->tensors
.parameters[dest_d]) & ~(uintptr_t)1))
;
2981 assert(dest)((void) sizeof ((dest) ? 1 : 0), __extension__ ({ if (dest) ;
else __assert_fail ("dest", "ccv_cnnp_model.c", 2981, __extension__
__PRETTY_FUNCTION__); }))
;
2982 inputs[0] = outputs[0] = dest;
2983 inputs[1] = src;
2984 ccv_nnc_cmd_exec(cmd, hint, flags, inputs, aux_in_size + 2, outputs, aux_out_size + 1, stream_context);
2985 }
2986 // Mark this symbol as init'ed.
2987 const int d = ((ccv_nnc_tensor_symbol_t*)ccv_array_get(to_compiled_data->parameters, dest_d)((void*)(((char*)((to_compiled_data->parameters)->data)
) + (size_t)(to_compiled_data->parameters)->rsize * (size_t
)(dest_d)))
)->d;
2988 to_init_v[d >> 5] |= (1u << (d & 0x1f));
2989 }
2990 ccv_array_free(to_parameter_indices);
2991 ccv_array_free(from_parameter_indices);
2992}
2993
2994void ccv_cnnp_model_parameters_map(ccv_cnnp_model_t* const model, const ccv_cnnp_model_io_t parameters, const ccv_nnc_cmd_t cmd, const ccv_nnc_hint_t hint, const int flags, ccv_nnc_tensor_t* const* const aux_ins, const int aux_in_size, ccv_nnc_tensor_t* const* const aux_outs, const int aux_out_size, ccv_nnc_stream_context_t* const stream_context)
2995{
2996 int to_param_ref;
2997 ccv_array_t* const to_parameter_indices = _ccv_cnnp_model_parameter_indices(model, parameters, &to_param_ref);
2998 // To models.
2999 ccv_cnnp_compiled_data_t* const to_compiled_data = model->compiled_data;
3000 assert(to_compiled_data)((void) sizeof ((to_compiled_data) ? 1 : 0), __extension__ ({
if (to_compiled_data) ; else __assert_fail ("to_compiled_data"
, "ccv_cnnp_model.c", 3000, __extension__ __PRETTY_FUNCTION__
); }))
;
3001 // Tensor has to be inited already.
3002 assert(!!to_compiled_data->tensors_init.v)((void) sizeof ((!!to_compiled_data->tensors_init.v) ? 1 :
0), __extension__ ({ if (!!to_compiled_data->tensors_init
.v) ; else __assert_fail ("!!to_compiled_data->tensors_init.v"
, "ccv_cnnp_model.c", 3002, __extension__ __PRETTY_FUNCTION__
); }))
;
3003 assert(to_compiled_data->tensors.parameters)((void) sizeof ((to_compiled_data->tensors.parameters) ? 1
: 0), __extension__ ({ if (to_compiled_data->tensors.parameters
) ; else __assert_fail ("to_compiled_data->tensors.parameters"
, "ccv_cnnp_model.c", 3003, __extension__ __PRETTY_FUNCTION__
); }))
;
3004 // From models.
3005 const int parallel_count = ccv_max(model->parallel_count, 1)({ typeof (model->parallel_count) _a = (model->parallel_count
); typeof (1) _b = (1); (_a > _b) ? _a : _b; })
;
3006 const int to_parameter_size = to_compiled_data->parameters->rnum;
3007 const int rnum = (to_param_ref < 0) ? to_parameter_indices->rnum : 1;
3008 assert(aux_in_size >= 0)((void) sizeof ((aux_in_size >= 0) ? 1 : 0), __extension__
({ if (aux_in_size >= 0) ; else __assert_fail ("aux_in_size >= 0"
, "ccv_cnnp_model.c", 3008, __extension__ __PRETTY_FUNCTION__
); }))
;
3009 assert(aux_out_size >= 0)((void) sizeof ((aux_out_size >= 0) ? 1 : 0), __extension__
({ if (aux_out_size >= 0) ; else __assert_fail ("aux_out_size >= 0"
, "ccv_cnnp_model.c", 3009, __extension__ __PRETTY_FUNCTION__
); }))
;
3010 int i, j;
3011 ccv_nnc_tensor_t* inputs[aux_in_size + 1];
3012 ccv_nnc_tensor_t* outputs[aux_out_size + 1];
3013 for (i = 0; i < aux_in_size; i++)
3014 inputs[i + 1] = aux_ins[i];
3015 for (i = 0; i < aux_out_size; i++)
3016 outputs[i + 1] = aux_outs[i];
3017 for (i = 0; i < rnum; i++)
3018 {
3019 const int dest_d = *(int*)ccv_array_get(to_parameter_indices, to_param_ref >= 0 ? to_param_ref : i)((void*)(((char*)((to_parameter_indices)->data)) + (size_t
)(to_parameter_indices)->rsize * (size_t)(to_param_ref >=
0 ? to_param_ref : i)))
;
3020 assert(dest_d >= 0)((void) sizeof ((dest_d >= 0) ? 1 : 0), __extension__ ({ if
(dest_d >= 0) ; else __assert_fail ("dest_d >= 0", "ccv_cnnp_model.c"
, 3020, __extension__ __PRETTY_FUNCTION__); }))
;
3021 assert(dest_d < to_compiled_data->parameters->rnum)((void) sizeof ((dest_d < to_compiled_data->parameters->
rnum) ? 1 : 0), __extension__ ({ if (dest_d < to_compiled_data
->parameters->rnum) ; else __assert_fail ("dest_d < to_compiled_data->parameters->rnum"
, "ccv_cnnp_model.c", 3021, __extension__ __PRETTY_FUNCTION__
); }))
;
3022 if (parallel_count > 1)
3023 {
3024 ccv_nnc_stream_context_t* streams[parallel_count];
3025 ccv_nnc_stream_signal_t* signal;
3026 if (stream_context)
3027 signal = ccv_nnc_stream_context_emit_signal_new(stream_context);
3028 for (j = 0; j < parallel_count; j++)
3029 {
3030 ccv_nnc_tensor_t* const dest = CCV_NNC_TENSOR(to_compiled_data->tensors.parameters[dest_d + j * to_parameter_size])((ccv_nnc_tensor_t*)((uintptr_t)(to_compiled_data->tensors
.parameters[dest_d + j * to_parameter_size]) & ~(uintptr_t
)1))
;
3031 if (!dest)
3032 {
3033 streams[j] = 0;
3034 continue;
3035 }
3036 const int stream_type = CCV_TENSOR_GET_MEMORY(dest->info.type)((dest->info.type) & 0x3) == CCV_TENSOR_GPU_MEMORY ? CCV_STREAM_CONTEXT_GPU : CCV_STREAM_CONTEXT_CPU;
3037 const int device_id = CCV_TENSOR_GET_DEVICE_ID(dest->info.type)(((dest->info.type) & 0xfff00) >> 8);
3038 int type = stream_type;
3039 CCV_STREAM_SET_DEVICE_ID(type, device_id)(type) = (((type) & ~0xfff00) | (((device_id) & 0xfff
) << 8))
;
3040 ccv_nnc_stream_context_t* const stream_0 = ccv_cnnp_compiled_data_get_stream(to_compiled_data, type);
3041 // Wait signal to finish.
3042 if (stream_context)
3043 ccv_nnc_stream_context_wait_signal(stream_0, signal);
3044 inputs[0] = outputs[0] = dest;
3045 ccv_nnc_cmd_exec(cmd, hint, flags, inputs, aux_in_size + 1, outputs, aux_out_size + 1, stream_0);
3046 if (stream_context)
3047 {
3048 ccv_nnc_stream_signal_t* const signal = ccv_nnc_stream_context_emit_signal_new(stream_0);
3049 ccv_nnc_stream_context_wait_signal(stream_context, signal);
3050 }
3051 streams[j] = stream_0;
3052 }
3053 // If this should be blocking, blocking it.
3054 if (!stream_context)
3055 for (j = 0; j < parallel_count; j++)
3056 if (streams[j])
3057 ccv_nnc_stream_context_wait(streams[j]);
3058 } else {
3059 ccv_nnc_tensor_t* const dest = CCV_NNC_TENSOR(to_compiled_data->tensors.parameters[dest_d])((ccv_nnc_tensor_t*)((uintptr_t)(to_compiled_data->tensors
.parameters[dest_d]) & ~(uintptr_t)1))
;
3060 assert(dest)((void) sizeof ((dest) ? 1 : 0), __extension__ ({ if (dest) ;
else __assert_fail ("dest", "ccv_cnnp_model.c", 3060, __extension__
__PRETTY_FUNCTION__); }))
;
3061 inputs[0] = outputs[0] = dest;
3062 ccv_nnc_cmd_exec(cmd, hint, flags, inputs, aux_in_size + 1, outputs, aux_out_size + 1, stream_context);
3063 }
3064 // No need to mark this symbol as init'ed, it is already.
3065 }
3066 ccv_array_free(to_parameter_indices);
3067}
3068
3069void ccv_cnnp_model_parameter_gradients_map(ccv_cnnp_model_t* const model, const ccv_cnnp_model_io_t parameters, const ccv_nnc_cmd_t cmd, const ccv_nnc_hint_t hint, const int flags, ccv_nnc_tensor_t* const* const aux_ins, const int aux_in_size, ccv_nnc_tensor_t* const* const aux_outs, const int aux_out_size, ccv_nnc_stream_context_t* const stream_context)
3070{
3071 int to_param_ref;
3072 ccv_array_t* const to_parameter_indices = _ccv_cnnp_model_parameter_indices(model, parameters, &to_param_ref);
3073 // To models.
3074 ccv_cnnp_compiled_data_t* const to_compiled_data = model->compiled_data;
3075 assert(to_compiled_data)((void) sizeof ((to_compiled_data) ? 1 : 0), __extension__ ({
if (to_compiled_data) ; else __assert_fail ("to_compiled_data"
, "ccv_cnnp_model.c", 3075, __extension__ __PRETTY_FUNCTION__
); }))
;
3076 // Tensor has to be inited already.
3077 assert(!!to_compiled_data->tensors_init.v)((void) sizeof ((!!to_compiled_data->tensors_init.v) ? 1 :
0), __extension__ ({ if (!!to_compiled_data->tensors_init
.v) ; else __assert_fail ("!!to_compiled_data->tensors_init.v"
, "ccv_cnnp_model.c", 3077, __extension__ __PRETTY_FUNCTION__
); }))
;
3078 ccv_nnc_tensor_t** tensor_gradients;
3079 if (to_compiled_data->backward.count > 1)
3080 tensor_gradients = to_compiled_data->tensors.accum_gradients;
3081 else
3082 tensor_gradients = to_compiled_data->tensors.gradients;
3083 assert(tensor_gradients)((void) sizeof ((tensor_gradients) ? 1 : 0), __extension__ ({
if (tensor_gradients) ; else __assert_fail ("tensor_gradients"
, "ccv_cnnp_model.c", 3083, __extension__ __PRETTY_FUNCTION__
); }))
;
3084 // From models.
3085 const int parallel_count = ccv_max(model->parallel_count, 1)({ typeof (model->parallel_count) _a = (model->parallel_count
); typeof (1) _b = (1); (_a > _b) ? _a : _b; })
;
3086 const int to_parameter_size = to_compiled_data->parameters->rnum;
3087 const int rnum = (to_param_ref < 0) ? to_parameter_indices->rnum : 1;
3088 assert(aux_in_size >= 0)((void) sizeof ((aux_in_size >= 0) ? 1 : 0), __extension__
({ if (aux_in_size >= 0) ; else __assert_fail ("aux_in_size >= 0"
, "ccv_cnnp_model.c", 3088, __extension__ __PRETTY_FUNCTION__
); }))
;
3089 assert(aux_out_size >= 0)((void) sizeof ((aux_out_size >= 0) ? 1 : 0), __extension__
({ if (aux_out_size >= 0) ; else __assert_fail ("aux_out_size >= 0"
, "ccv_cnnp_model.c", 3089, __extension__ __PRETTY_FUNCTION__
); }))
;
3090 int i, j;
3091 ccv_nnc_tensor_t* inputs[aux_in_size + 1];
3092 ccv_nnc_tensor_t* outputs[aux_out_size + 1];
3093 for (i = 0; i < aux_in_size; i++)
3094 inputs[i + 1] = aux_ins[i];
3095 for (i = 0; i < aux_out_size; i++)
3096 outputs[i + 1] = aux_outs[i];
3097 for (i = 0; i < rnum; i++)
3098 {
3099 const int dest_d = *(int*)ccv_array_get(to_parameter_indices, to_param_ref >= 0 ? to_param_ref : i)((void*)(((char*)((to_parameter_indices)->data)) + (size_t
)(to_parameter_indices)->rsize * (size_t)(to_param_ref >=
0 ? to_param_ref : i)))
;
3100 assert(dest_d >= 0)((void) sizeof ((dest_d >= 0) ? 1 : 0), __extension__ ({ if
(dest_d >= 0) ; else __assert_fail ("dest_d >= 0", "ccv_cnnp_model.c"
, 3100, __extension__ __PRETTY_FUNCTION__); }))
;
3101 assert(dest_d < to_compiled_data->parameters->rnum)((void) sizeof ((dest_d < to_compiled_data->parameters->
rnum) ? 1 : 0), __extension__ ({ if (dest_d < to_compiled_data
->parameters->rnum) ; else __assert_fail ("dest_d < to_compiled_data->parameters->rnum"
, "ccv_cnnp_model.c", 3101, __extension__ __PRETTY_FUNCTION__
); }))
;
3102 if (parallel_count > 1)
3103 {
3104 ccv_nnc_stream_context_t* streams[parallel_count];
3105 ccv_nnc_stream_signal_t* signal;
3106 if (stream_context)
3107 signal = ccv_nnc_stream_context_emit_signal_new(stream_context);
3108 for (j = 0; j < parallel_count; j++)
3109 {
3110 ccv_nnc_tensor_t* const dest = tensor_gradients[dest_d + j * to_parameter_size];
3111 if (!dest)
3112 {
3113 streams[j] = 0;
3114 continue;
3115 }
3116 const int stream_type = CCV_TENSOR_GET_MEMORY(dest->info.type)((dest->info.type) & 0x3) == CCV_TENSOR_GPU_MEMORY ? CCV_STREAM_CONTEXT_GPU : CCV_STREAM_CONTEXT_CPU;
3117 const int device_id = CCV_TENSOR_GET_DEVICE_ID(dest->info.type)(((dest->info.type) & 0xfff00) >> 8);
3118 int type = stream_type;
3119 CCV_STREAM_SET_DEVICE_ID(type, device_id)(type) = (((type) & ~0xfff00) | (((device_id) & 0xfff
) << 8))
;
3120 ccv_nnc_stream_context_t* const stream_0 = ccv_cnnp_compiled_data_get_stream(to_compiled_data, type);
3121 // Wait signal to finish.
3122 if (stream_context)
3123 ccv_nnc_stream_context_wait_signal(stream_0, signal);
3124 inputs[0] = outputs[0] = dest;
3125 ccv_nnc_cmd_exec(cmd, hint, flags, inputs, aux_in_size + 1, outputs, aux_out_size + 1, stream_0);
3126 if (stream_context)
3127 {
3128 ccv_nnc_stream_signal_t* const signal = ccv_nnc_stream_context_emit_signal_new(stream_0);
3129 ccv_nnc_stream_context_wait_signal(stream_context, signal);
3130 }
3131 streams[j] = stream_0;
3132 }
3133 // If this should be blocking, blocking it.
3134 if (!stream_context)
3135 for (j = 0; j < parallel_count; j++)
3136 if (streams[j])
3137 ccv_nnc_stream_context_wait(streams[j]);
3138 } else {
3139 ccv_nnc_tensor_t* const dest = tensor_gradients[dest_d];
3140 if (!dest)
3141 continue;
3142 assert(dest)((void) sizeof ((dest) ? 1 : 0), __extension__ ({ if (dest) ;
else __assert_fail ("dest", "ccv_cnnp_model.c", 3142, __extension__
__PRETTY_FUNCTION__); }))
;
3143 inputs[0] = outputs[0] = dest;
3144 ccv_nnc_cmd_exec(cmd, hint, flags, inputs, aux_in_size + 1, outputs, aux_out_size + 1, stream_context);
3145 }
3146 // No need to mark this symbol as init'ed, it is already.
3147 }
3148 ccv_array_free(to_parameter_indices);
3149}
3150
3151void ccv_cnnp_model_parameters_to_unified_memory(ccv_cnnp_model_t* const model, const ccv_cnnp_model_io_t parameters, ccv_nnc_stream_context_t* const stream_context)
3152{
3153 // Only CUDA backend has this feature.
3154#ifdef HAVE_CUDA1
3155 int to_param_ref;
3156 ccv_array_t* const to_parameter_indices = _ccv_cnnp_model_parameter_indices(model, parameters, &to_param_ref);
3157 // To models.
3158 ccv_cnnp_compiled_data_t* const compiled_data = model->compiled_data;
3159 assert(compiled_data)((void) sizeof ((compiled_data) ? 1 : 0), __extension__ ({ if
(compiled_data) ; else __assert_fail ("compiled_data", "ccv_cnnp_model.c"
, 3159, __extension__ __PRETTY_FUNCTION__); }))
;
3160 // Tensor has to be inited already.
3161 assert(!!compiled_data->tensors_init.v)((void) sizeof ((!!compiled_data->tensors_init.v) ? 1 : 0)
, __extension__ ({ if (!!compiled_data->tensors_init.v) ; else
__assert_fail ("!!compiled_data->tensors_init.v", "ccv_cnnp_model.c"
, 3161, __extension__ __PRETTY_FUNCTION__); }))
;
3162 assert(compiled_data->tensors.parameters)((void) sizeof ((compiled_data->tensors.parameters) ? 1 : 0
), __extension__ ({ if (compiled_data->tensors.parameters)
; else __assert_fail ("compiled_data->tensors.parameters"
, "ccv_cnnp_model.c", 3162, __extension__ __PRETTY_FUNCTION__
); }))
;
3163 // From models.
3164 const int parallel_count = ccv_max(model->parallel_count, 1)({ typeof (model->parallel_count) _a = (model->parallel_count
); typeof (1) _b = (1); (_a > _b) ? _a : _b; })
;
3165 const int rnum = (to_param_ref < 0) ? to_parameter_indices->rnum : 1;
3166 int i;
3167 for (i = 0; i < rnum; i++)
3168 {
3169 const int dest_d = *(int*)ccv_array_get(to_parameter_indices, to_param_ref >= 0 ? to_param_ref : i)((void*)(((char*)((to_parameter_indices)->data)) + (size_t
)(to_parameter_indices)->rsize * (size_t)(to_param_ref >=
0 ? to_param_ref : i)))
;
3170 assert(dest_d >= 0)((void) sizeof ((dest_d >= 0) ? 1 : 0), __extension__ ({ if
(dest_d >= 0) ; else __assert_fail ("dest_d >= 0", "ccv_cnnp_model.c"
, 3170, __extension__ __PRETTY_FUNCTION__); }))
;
3171 assert(dest_d < compiled_data->parameters->rnum)((void) sizeof ((dest_d < compiled_data->parameters->
rnum) ? 1 : 0), __extension__ ({ if (dest_d < compiled_data
->parameters->rnum) ; else __assert_fail ("dest_d < compiled_data->parameters->rnum"
, "ccv_cnnp_model.c", 3171, __extension__ __PRETTY_FUNCTION__
); }))
;
3172 if (parallel_count > 1)
3173 {
3174 assert(0 && "Cannot support this when data parallel is in effect.")((void) sizeof ((0 && "Cannot support this when data parallel is in effect."
) ? 1 : 0), __extension__ ({ if (0 && "Cannot support this when data parallel is in effect."
) ; else __assert_fail ("0 && \"Cannot support this when data parallel is in effect.\""
, "ccv_cnnp_model.c", 3174, __extension__ __PRETTY_FUNCTION__
); }))
;
3175 } else {
3176 ccv_nnc_tensor_t* const src = CCV_NNC_TENSOR(compiled_data->tensors.parameters[dest_d])((ccv_nnc_tensor_t*)((uintptr_t)(compiled_data->tensors.parameters
[dest_d]) & ~(uintptr_t)1))
;
3177 assert(src)((void) sizeof ((src) ? 1 : 0), __extension__ ({ if (src) ; else
__assert_fail ("src", "ccv_cnnp_model.c", 3177, __extension__
__PRETTY_FUNCTION__); }))
;
3178 ccv_nnc_tensor_param_t params = src->info;
3179 if (CCV_TENSOR_GET_MEMORY(params.type)((params.type) & 0x3) != CCV_TENSOR_GPU_MEMORY)
3180 continue;
3181 const size_t size = ccv_nnc_tensor_data_size(params);
3182 if (size <= 0)
3183 continue;
3184 const int should_free = !((uintptr_t)compiled_data->tensors.parameters[dest_d] & (uintptr_t)1);
3185 const int tfb = (CCV_TENSOR_GET_MEMORY(params.type)((params.type) & 0x3) == CCV_TENSOR_CPU_MEMORY && params.format == CCV_TENSOR_FORMAT_NHWC && params.dim[2] > 0 && params.dim[2] <= CCV_MAX_CHANNEL(0xFFF) && params.dim[0] > 0 && params.dim[1] > 0 && params.dim[3] == 0);
3186 ccv_nnc_tensor_t* const tensor = (ccv_nnc_tensor_t*)ccmallocmalloc(sizeof(ccv_nnc_tensor_t));
3187 tensor->dataof = 0;
3188 tensor->alias_ref = 0;
3189 tensor->sig = 0;
3190 tensor->refcount = 1;
3191 tensor->info = params;
3192 if (tfb)
3193 {
3194 tensor->type = CCV_NO_DATA_ALLOC | CCV_MATRIX_DENSE | CCV_GET_DATA_TYPE(params.datatype)((params.datatype) & 0xFF000) | params.dim[2];
3195 // This corresponding to mat->step
3196 tensor->info.dim[4] = CCV_GET_STEP(params.dim[1], (CCV_GET_DATA_TYPE(params.datatype) | params.dim[2]))(((params.dim[1]) * _ccv_get_data_type_size[(((((params.datatype
) & 0xFF000) | params.dim[2])) & 0xFF000) >> 12
] * (((((params.datatype) & 0xFF000) | params.dim[2])) &
0xFFF) + 3) & -4)
;
3197 } else // This won't be recognized by ccv_dense_matrix_t
3198 tensor->type = CCV_NO_DATA_ALLOC | CCV_MATRIX_DENSE | CCV_GET_DATA_TYPE(params.datatype)((params.datatype) & 0xFF000);
3199 // Remove this flag so it can be deallocated as usual.
3200 tensor->type &= ~CCV_NO_DATA_ALLOC;
3201 assert(CCV_TENSOR_GET_DEVICE(params.type) != CCV_COMPUTE_DEVICE_ANY)((void) sizeof ((((params.type) & 0xfff00) != CCV_COMPUTE_DEVICE_ANY
) ? 1 : 0), __extension__ ({ if (((params.type) & 0xfff00
) != CCV_COMPUTE_DEVICE_ANY) ; else __assert_fail ("CCV_TENSOR_GET_DEVICE(params.type) != CCV_COMPUTE_DEVICE_ANY"
, "ccv_cnnp_model.c", 3201, __extension__ __PRETTY_FUNCTION__
); }))
;
3202 void* ptr = cumallocmanaged(CCV_TENSOR_GET_DEVICE_ID(params.type)(((params.type) & 0xfff00) >> 8), size);
3203 if (ptr) // If allocated successfully. Otherwise we go through the fallback path.
3204 {
3205 tensor->data.u8 = (uint8_t*)ptr;
3206 tensor->type |= CCV_MAPPED_MEM; // This denotes the tensor is mapped to CPU, and would prefer a explicit prefetch call.
3207 } else {
3208 // Allocation failed.
3209 ccfreefree(tensor);
3210 continue;
3211 }
3212 // TODO: Cannot run this on the stream context yet, due to allocation and deallocations.
3213 ccv_nnc_cmd_exec(CMD_DATA_TRANSFER_FORWARD()ccv_nnc_cmd(CCV_NNC_DATA_TRANSFER_FORWARD, 0, ccv_nnc_cmd_auto
, 0)
, ccv_nnc_no_hint, 0, &src, 1, &tensor, 1, 0);
3214 cumemadvisereadmostly(CCV_TENSOR_GET_DEVICE_ID(params.type)(((params.type) & 0xfff00) >> 8), tensor->data.u8, size);
3215 compiled_data->tensors.parameters[dest_d] = tensor;
3216 // Can free out the old one.
3217 if (should_free)
3218 ccv_nnc_tensor_free(src);
3219 }
3220 // No need to mark this symbol as init'ed, it is already.
3221 }
3222 ccv_array_free(to_parameter_indices);
3223#endif
3224}
3225
3226ccv_nnc_cmd_t ccv_cnnp_model_minimizer(ccv_cnnp_model_t* const model)
3227{
3228 ccv_cnnp_compiled_data_t* const compiled_data = model->compiled_data;
3229 assert(compiled_data)((void) sizeof ((compiled_data) ? 1 : 0), __extension__ ({ if
(compiled_data) ; else __assert_fail ("compiled_data", "ccv_cnnp_model.c"
, 3229, __extension__ __PRETTY_FUNCTION__); }))
;
3230 return compiled_data->minimize.minimizer;
3231}
3232
3233void ccv_cnnp_model_set_minimizer(ccv_cnnp_model_t* const model, const ccv_nnc_cmd_t minimizer, const int reset, const ccv_cnnp_model_io_t* const set_parameters, const int set_parameter_size)
3234{
3235 ccv_cnnp_compiled_data_t* const compiled_data = model->compiled_data;
3236 assert(compiled_data)((void) sizeof ((compiled_data) ? 1 : 0), __extension__ ({ if
(compiled_data) ; else __assert_fail ("compiled_data", "ccv_cnnp_model.c"
, 3236, __extension__ __PRETTY_FUNCTION__); }))
;
3237 const int parameter_size = compiled_data->parameters->rnum;
3238 if (parameter_size == 0)
3239 return;
3240 if (reset)
3241 { assert(set_parameters == 0 && set_parameter_size == 0)((void) sizeof ((set_parameters == 0 && set_parameter_size
== 0) ? 1 : 0), __extension__ ({ if (set_parameters == 0 &&
set_parameter_size == 0) ; else __assert_fail ("set_parameters == 0 && set_parameter_size == 0"
, "ccv_cnnp_model.c", 3241, __extension__ __PRETTY_FUNCTION__
); }))
; }
3242 const int old_max_saved_aux_size = compiled_data->minimize.max_saved_aux_size;
3243 const int saved_aux_size = ccv_nnc_minimizer_saved_aux_size(minimizer);
3244 if (saved_aux_size > compiled_data->minimize.max_saved_aux_size)
3245 compiled_data->minimize.max_saved_aux_size = saved_aux_size;
3246 const int max_saved_aux_size = compiled_data->minimize.max_saved_aux_size;
3247 // We update all parameters, at this point, we have one minimizer.
3248 if (set_parameters == 0 || set_parameter_size == 0)
3249 compiled_data->minimize.minimizer = minimizer;
3250 int i;
3251 if (set_parameters && set_parameter_size)
3252 {
3253 // I need to save what's the minimizer along with this.
3254 if (!compiled_data->minimize.parameters)
3255 compiled_data->minimize.parameters = ccv_array_new(sizeof(ccv_cnnp_set_minimizer_for_parameter_t*), 1, 0);
3256 ccv_cnnp_set_minimizer_for_parameter_t* const set_minimizer_for_parameter = ccmallocmalloc(sizeof(ccv_cnnp_set_minimizer_for_parameter_t) + (set_parameter_size - 1) * sizeof(ccv_cnnp_model_io_t));
3257 set_minimizer_for_parameter->minimizer = minimizer;
3258 set_minimizer_for_parameter->parameter_size = set_parameter_size;
3259 memcpy(set_minimizer_for_parameter->parameters, set_parameters, sizeof(ccv_cnnp_model_io_t) * set_parameter_size);
3260 ccv_array_push(compiled_data->minimize.parameters, &set_minimizer_for_parameter);
3261 }
3262 // If reset is true, clear the parameters array.
3263 if (reset && compiled_data->minimize.parameters)
3264 {
3265 for (i = 0; i < compiled_data->minimize.parameters->rnum; i++)
3266 ccfreefree(*(ccv_cnnp_set_minimizer_for_parameter_t**)ccv_array_get(compiled_data->minimize.parameters, i)((void*)(((char*)((compiled_data->minimize.parameters)->
data)) + (size_t)(compiled_data->minimize.parameters)->
rsize * (size_t)(i)))
);
3267 ccv_array_clear(compiled_data->minimize.parameters);
3268 }
3269 if (!compiled_data->update_nodes)
3270 return;
3271 ccv_nnc_symbolic_graph_t* const symbolic_graph = model->graph;
3272 assert(symbolic_graph)((void) sizeof ((symbolic_graph) ? 1 : 0), __extension__ ({ if
(symbolic_graph) ; else __assert_fail ("symbolic_graph", "ccv_cnnp_model.c"
, 3272, __extension__ __PRETTY_FUNCTION__); }))
;
3273 if (saved_aux_size > old_max_saved_aux_size)
3274 {
3275 assert(compiled_data->updated_parameters)((void) sizeof ((compiled_data->updated_parameters) ? 1 : 0
), __extension__ ({ if (compiled_data->updated_parameters)
; else __assert_fail ("compiled_data->updated_parameters"
, "ccv_cnnp_model.c", 3275, __extension__ __PRETTY_FUNCTION__
); }))
;
3276 // Reallocate first, move them around later.
3277 compiled_data->updated_parameters = (ccv_nnc_tensor_symbol_t*)ccreallocrealloc(compiled_data->updated_parameters, sizeof(ccv_nnc_tensor_symbol_t) * parameter_size + sizeof(ccv_nnc_graph_exec_symbol_t) * parameter_size + sizeof(ccv_nnc_tensor_symbol_map_t) * saved_aux_size * parameter_size);
3278 compiled_data->update_nodes = (ccv_nnc_graph_exec_symbol_t*)(compiled_data->updated_parameters + parameter_size);
3279 compiled_data->saved_aux = (ccv_nnc_tensor_symbol_map_t*)(compiled_data->update_nodes + parameter_size);
3280 // We need to do this from back to front because saved_aux_size > old_saved_aux_size, it could overlap.
3281 _ccv_cnnp_scatter_saved_aux(compiled_data->saved_aux, parameter_size, old_max_saved_aux_size, saved_aux_size);
3282 }
3283 int flag = 0;
3284 const int parallel_count = ccv_max(model->parallel_count, 1)({ typeof (model->parallel_count) _a = (model->parallel_count
); typeof (1) _b = (1); (_a > _b) ? _a : _b; })
;
3285 if (set_parameters && set_parameter_size)
3286 {
3287 ccv_array_t* const parameter_indices = ccv_array_new(sizeof(int), 0, 0);
3288 for (i = 0; i < set_parameter_size; i++)
3289 {
3290 const int param_sel = set_parameters[i]->param_sel > 0 ? set_parameters[i]->param_sel - 1 : set_parameters[i]->param_sel;
3291 assert(set_parameters[i]->param_sel != 0)((void) sizeof ((set_parameters[i]->param_sel != 0) ? 1 : 0
), __extension__ ({ if (set_parameters[i]->param_sel != 0)
; else __assert_fail ("set_parameters[i]->param_sel != 0"
, "ccv_cnnp_model.c", 3291, __extension__ __PRETTY_FUNCTION__
); }))
;
3292 const int old_rnum = parameter_indices->rnum;
3293 ccv_cnnp_model_add_to_parameter_indices(set_parameters[i]->model, param_sel, parameter_indices);
3294 const int param_ref = set_parameters[i]->param_ref > 0 ? set_parameters[i]->param_ref - 1 : set_parameters[i]->param_ref;
3295 assert(set_parameters[i]->param_ref != 0)((void) sizeof ((set_parameters[i]->param_ref != 0) ? 1 : 0
), __extension__ ({ if (set_parameters[i]->param_ref != 0)
; else __assert_fail ("set_parameters[i]->param_ref != 0"
, "ccv_cnnp_model.c", 3295, __extension__ __PRETTY_FUNCTION__
); }))
;
3296 if (param_ref >= 0)
3297 {
3298 assert(param_ref + old_rnum < parameter_indices->rnum)((void) sizeof ((param_ref + old_rnum < parameter_indices->
rnum) ? 1 : 0), __extension__ ({ if (param_ref + old_rnum <
parameter_indices->rnum) ; else __assert_fail ("param_ref + old_rnum < parameter_indices->rnum"
, "ccv_cnnp_model.c", 3298, __extension__ __PRETTY_FUNCTION__
); }))
;
3299 *(int*)ccv_array_get(parameter_indices, old_rnum)((void*)(((char*)((parameter_indices)->data)) + (size_t)(parameter_indices
)->rsize * (size_t)(old_rnum)))
= *(int*)ccv_array_get(parameter_indices, param_ref + old_rnum)((void*)(((char*)((parameter_indices)->data)) + (size_t)(parameter_indices
)->rsize * (size_t)(param_ref + old_rnum)))
;
3300 parameter_indices->rnum = old_rnum + 1;
3301 }
3302 }
3303 // We may have duplicated indices, but that is OK, we will set it twice.
3304 for (i = 0; i < parameter_indices->rnum; i++)
3305 {
3306 const int d = *(int*)ccv_array_get(parameter_indices, i)((void*)(((char*)((parameter_indices)->data)) + (size_t)(parameter_indices
)->rsize * (size_t)(i)))
;
3307 if (_ccv_cnnp_set_minimizer_for_parameter(symbolic_graph, compiled_data, compiled_data->update_nodes, compiled_data->updated_parameters, compiled_data->saved_aux, parallel_count, minimizer, saved_aux_size, max_saved_aux_size, d))
3308 flag = 1;
3309 }
3310 ccv_array_free(parameter_indices);
3311 } else {
3312 for (i = 0; i < parameter_size; i++)
3313 if (_ccv_cnnp_set_minimizer_for_parameter(symbolic_graph, compiled_data, compiled_data->update_nodes, compiled_data->updated_parameters, compiled_data->saved_aux, parallel_count, minimizer, saved_aux_size, max_saved_aux_size, i))
3314 flag = 1;
3315 if (compiled_data->minimize.parameters)
3316 if (_ccv_cnnp_apply_parameters_with_minimizer(model))
3317 flag = 1;
3318 }
3319 if (flag)
3320 {
3321 // If saved_aux_size doesn't match, we need to remove / add new saved_aux to the graph. But first, free up apply gradients graph.
3322 if (compiled_data->graph_mode == CCV_CNNP_MODEL_GRAPH_FIT_MODE)
3323 _ccv_cnnp_compiled_data_graph_free(compiled_data);
3324 _ccv_cnnp_compiled_data_apply_gradients_free(compiled_data);
3325 }
3326}
3327
3328void ccv_cnnp_model_set_compile_params(ccv_cnnp_model_t* const model, const ccv_nnc_symbolic_graph_compile_param_t compile_params)
3329{
3330 ccv_cnnp_compiled_data_t* const compiled_data = model->compiled_data;
3331 assert(compiled_data)((void) sizeof ((compiled_data) ? 1 : 0), __extension__ ({ if
(compiled_data) ; else __assert_fail ("compiled_data", "ccv_cnnp_model.c"
, 3331, __extension__ __PRETTY_FUNCTION__); }))
;
3332 compiled_data->compile_params = compile_params;
3333}
3334
3335void ccv_cnnp_model_dot(const ccv_cnnp_model_t* const model, const int flags, FILE** const outs, const int out_size)
3336{
3337 if (model->graph && out_size > 0)
3338 ccv_nnc_symbolic_graph_dot(model->graph, flags, outs[0]);
3339 if (model->compiled_data && model->compiled_data->graph && out_size > 1)
3340 ccv_nnc_graph_dot(model->compiled_data->graph, flags, outs[1]);
3341 if (model->compiled_data && model->compiled_data->backward.accum && out_size > 2)
3342 ccv_nnc_graph_dot(model->compiled_data->backward.accum, flags, outs[2]);
3343 if (model->compiled_data && model->compiled_data->apply_gradients.graph && out_size > 3)
3344 ccv_nnc_graph_dot(model->compiled_data->apply_gradients.graph, flags, outs[3]);
3345}
3346
3347void ccv_cnnp_model_format(const ccv_cnnp_model_t* const model, const ccv_nnc_symbolic_graph_format_f format_fn, void* const context)
3348{
3349 if (model->graph)
3350 ccv_nnc_symbolic_graph_format(model->graph, 0, 0, 0, 0, format_fn, context);
3351}
3352
3353static void _ccv_cnnp_compiled_data_free(const ccv_cnnp_model_t* const model, ccv_cnnp_compiled_data_t* const compiled_data)
3354{
3355 int i;
3356 const int parameter_size = compiled_data->parameters->rnum;
3357 ccv_array_free(compiled_data->parameters);
3358 if (compiled_data->parameter_flags)
3359 ccfreefree(compiled_data->parameter_flags);
3360 const int internal_size = compiled_data->internals->rnum;
3361 ccv_array_free(compiled_data->internals);
3362 assert(compiled_data->ids.parameters->rnum == parameter_size)((void) sizeof ((compiled_data->ids.parameters->rnum ==
parameter_size) ? 1 : 0), __extension__ ({ if (compiled_data
->ids.parameters->rnum == parameter_size) ; else __assert_fail
("compiled_data->ids.parameters->rnum == parameter_size"
, "ccv_cnnp_model.c", 3362, __extension__ __PRETTY_FUNCTION__
); }))
;
3363 assert(compiled_data->ids.internals->rnum == internal_size)((void) sizeof ((compiled_data->ids.internals->rnum == internal_size
) ? 1 : 0), __extension__ ({ if (compiled_data->ids.internals
->rnum == internal_size) ; else __assert_fail ("compiled_data->ids.internals->rnum == internal_size"
, "ccv_cnnp_model.c", 3363, __extension__ __PRETTY_FUNCTION__
); }))
;
3364 for (i = 0; i < parameter_size; i++)
3365 ccfreefree(*(char**)ccv_array_get(compiled_data->ids.parameters, i)((void*)(((char*)((compiled_data->ids.parameters)->data
)) + (size_t)(compiled_data->ids.parameters)->rsize * (
size_t)(i)))
);
3366 ccv_array_free(compiled_data->ids.parameters);
3367 for (i = 0; i < internal_size; i++)
3368 ccfreefree(*(char**)ccv_array_get(compiled_data->ids.internals, i)((void*)(((char*)((compiled_data->ids.internals)->data)
) + (size_t)(compiled_data->ids.internals)->rsize * (size_t
)(i)))
);
3369 ccv_array_free(compiled_data->ids.internals);
3370 const int parallel_count = compiled_data->parallel_count > 0 ? compiled_data->parallel_count : _ccv_cnnp_model_root_parallel_count(model);
3371 if (compiled_data->tensors.parameters)
3372 {
3373 for (i = 0; i < parameter_size * parallel_count; i++)
3374 // If it is not marked as not belonging, we can free it.
3375 if (!((uintptr_t)compiled_data->tensors.parameters[i] & (uintptr_t)1))
3376 if (compiled_data->tensors.parameters[i])
3377 ccv_nnc_tensor_free(compiled_data->tensors.parameters[i]);
3378 for (i = 0; i < internal_size * parallel_count; i++)
3379 if (compiled_data->tensors.internals[i])
3380 ccv_nnc_tensor_free(compiled_data->tensors.internals[i]);
3381 ccfreefree(compiled_data->tensors.parameters);
3382 }
3383 if (compiled_data->tensors.gradients)
3384 {
3385 for (i = 0; i < parameter_size * parallel_count; i++)
3386 {
3387 if (compiled_data->tensors.gradients[i])
3388 ccv_nnc_tensor_free(compiled_data->tensors.gradients[i]);
3389 if (compiled_data->tensors.accum_gradients[i])
3390 ccv_nnc_tensor_free(compiled_data->tensors.accum_gradients[i]);
3391 }
3392 ccfreefree(compiled_data->tensors.gradients);
3393 }
3394 if (compiled_data->minimize.parameters)
3395 {
3396 for (i = 0; i < compiled_data->minimize.parameters->rnum; i++)
3397 ccfreefree(*(ccv_cnnp_set_minimizer_for_parameter_t**)ccv_array_get(compiled_data->minimize.parameters, i)((void*)(((char*)((compiled_data->minimize.parameters)->
data)) + (size_t)(compiled_data->minimize.parameters)->
rsize * (size_t)(i)))
);
3398 ccv_array_free(compiled_data->minimize.parameters);
3399 }
3400 if (compiled_data->rewindables)
3401 ccv_array_free(compiled_data->rewindables);
3402 if (compiled_data->tensors_init.v)
3403 ccfreefree(CCV_NNC_INIT_V(compiled_data->tensors_init.v)((uint32_t*)((uintptr_t)(compiled_data->tensors_init.v) &
~(uintptr_t)1))
);
3404 if (compiled_data->evaluate.tos)
3405 ccfreefree(compiled_data->evaluate.tos);
3406 compiled_data->evaluate.tos = 0;
3407 if (compiled_data->stream_map)
3408 {
3409 khiter_t k;
3410 for (k = kh_begin(compiled_data->stream_map)(khint_t)(0); k != kh_end(compiled_data->stream_map)((compiled_data->stream_map)->n_buckets); ++k)
3411 {
3412 if (!kh_exist(compiled_data->stream_map, k)(!(((compiled_data->stream_map)->flags[(k)>>4]>>
(((k)&0xfU)<<1))&3))
)
3413 continue;
3414 ccv_nnc_stream_context_t* const stream = kh_val(compiled_data->stream_map, k)((compiled_data->stream_map)->vals[k]);
3415 ccv_nnc_stream_context_free(stream);
3416 }
3417 kh_destroy(stream_map, compiled_data->stream_map)kh_destroy_stream_map(compiled_data->stream_map);
3418 }
3419 _ccv_cnnp_compiled_data_graph_free(compiled_data);
3420 _ccv_cnnp_compiled_data_gradient_free(compiled_data);
3421 _ccv_cnnp_compiled_data_backward_free(compiled_data);
3422 _ccv_cnnp_compiled_data_apply_gradients_free(compiled_data);
3423 if (compiled_data->gradient_checkpoints)
3424 {
3425 for (i = 0; i < compiled_data->gradient_checkpoints->rnum; i++)
3426 {
3427 ccv_cnnp_model_gradient_checkpoint_t* const checkpoint = (ccv_cnnp_model_gradient_checkpoint_t*)ccv_array_get(compiled_data->gradient_checkpoints, i)((void*)(((char*)((compiled_data->gradient_checkpoints)->
data)) + (size_t)(compiled_data->gradient_checkpoints)->
rsize * (size_t)(i)))
;
3428 assert(checkpoint->inputs)((void) sizeof ((checkpoint->inputs) ? 1 : 0), __extension__
({ if (checkpoint->inputs) ; else __assert_fail ("checkpoint->inputs"
, "ccv_cnnp_model.c", 3428, __extension__ __PRETTY_FUNCTION__
); }))
;
3429 ccfreefree(checkpoint->inputs);
3430 ccv_array_free(checkpoint->tensor_symbols);
3431 }
3432 ccv_array_free(compiled_data->gradient_checkpoints);
3433 }
3434 ccv_nnc_xpu_alloc_destroy(&compiled_data->xpu_alloc);
3435 ccfreefree(compiled_data);
3436}
3437
3438void ccv_cnnp_model_free(ccv_cnnp_model_t* const model)
3439{
3440 ccv_cnnp_model_deinit(model);
3441 if (model->isa->dealloc)
3442 model->isa->dealloc(model);
3443 if (model->io)
3444 {
3445 int i;
3446 for (i = 0; i < model->io->rnum; i++)
3447 {
3448 ccv_cnnp_model_io_t model_io = *(ccv_cnnp_model_io_t*)ccv_array_get(model->io, i)((void*)(((char*)((model->io)->data)) + (size_t)(model->
io)->rsize * (size_t)(i)))
;
3449 if (model_io->outgoings)
3450 ccv_array_free(model_io->outgoings);
3451 if (model_io->incomings)
3452 ccv_array_free(model_io->incomings);
3453 if (model_io->dependencies)
3454 ccv_array_free(model_io->dependencies);
3455 ccfreefree(model_io);
3456 }
3457 ccv_array_free(model->io);
3458 }
3459 if (model->parameter_indices)
3460 ccv_array_free(model->parameter_indices);
3461 if (model->inputs)
3462 ccfreefree(model->inputs);
3463 if (model->graph)
3464 ccv_nnc_symbolic_graph_free(model->graph);
3465 if (model->compiled_data)
3466 _ccv_cnnp_compiled_data_free(model, model->compiled_data);
3467 if (model->name)
3468 ccfreefree(model->name);
3469 ccfreefree(model);
3470}
3471
3472void ccv_cnnp_model_cancel(ccv_cnnp_model_t* const model)
3473{
3474 ccv_cnnp_compiled_data_t* const compiled_data = model->compiled_data;
3475 if (!compiled_data)
3476 return;
3477 if (compiled_data->graph)
3478 ccv_nnc_graph_cancel(compiled_data->graph);
3479 if (compiled_data->apply_gradients.graph)
3480 ccv_nnc_graph_cancel(compiled_data->apply_gradients.graph);
3481}
3482
3483void ccv_cnnp_model_async_enter(ccv_cnnp_model_t* const model)
3484{
3485 ccv_cnnp_compiled_data_t* const compiled_data = model->compiled_data;
3486 if (!compiled_data)
3487 return;
3488 if (compiled_data->graph)
3489 ccv_nnc_graph_async_enter(compiled_data->graph);
3490 if (compiled_data->apply_gradients.graph)
3491 ccv_nnc_graph_async_enter(compiled_data->apply_gradients.graph);
3492}
3493
3494void ccv_cnnp_model_set_flags(ccv_cnnp_model_t* const model, const int flags)
3495{
3496 model->exec_flags = flags;
3497}
3498
3499int ccv_cnnp_model_flags(ccv_cnnp_model_t* const model)
3500{
3501 return model->exec_flags;
3502}