Bug Summary

File:nnc/ccv_cnnp_model_core.c
Warning:line 487, 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_core.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-04-23-174101-1054636-1 -x c ccv_cnnp_model_core.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 "3rdparty/khash/khash.h"
7
8// MARK - Baisc Layers
9
10static const ccv_cnnp_model_vtab_t ccv_cnnp_input_isa;
11
12#define CCV_CNNP_IS_MODEL_INPUT(x)((x)->isa == &ccv_cnnp_input_isa) ((x)->isa == &ccv_cnnp_input_isa)
13
14#define CCV_CNNP_IS_MODEL_PARAMETER(x)((x)->param_ref != 0 || (x)->param_sel != 0) ((x)->param_ref != 0 || (x)->param_sel != 0)
15
16typedef struct {
17 ccv_cnnp_model_t super;
18 int sequence_size;
19 ccv_cnnp_model_t* sequence[1];
20} ccv_cnnp_sequential_model_t;
21
22static void _ccv_cnnp_sequential_model_deinit(ccv_cnnp_model_t* const super)
23{
24 ccv_cnnp_sequential_model_t* const self = (ccv_cnnp_sequential_model_t*)super;
25 int i, j = 0;
26 for (i = 0; i < self->sequence_size; i++)
27 {
28 ccv_cnnp_model_t* const model = self->sequence[i];
29 if (model->deinit_state)
30 continue;
31 ccv_cnnp_model_deinit(model);
32 self->sequence[j++] = model;
33 }
34 self->sequence_size = j;
35}
36
37static void _ccv_cnnp_sequential_model_dealloc(ccv_cnnp_model_t* const super)
38{
39 ccv_cnnp_sequential_model_t* const self = (ccv_cnnp_sequential_model_t*)super;
40 int i;
41 for (i = 0; i < self->sequence_size; i++)
42 ccv_cnnp_model_free(self->sequence[i]);
43}
44
45static void _ccv_cnnp_sequential_model_build(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_nnc_tensor_symbol_t* const inputs, const int input_size, ccv_nnc_tensor_symbol_t* const outputs, const int output_size)
46{
47 ccv_cnnp_sequential_model_t* const self = (ccv_cnnp_sequential_model_t*)super;
48 PRINT(CCV_CLI_VERBOSE, "[cnnp_sequential_model_build] 1. %p, sequence_size: %d\n", self, self->sequence_size)do { if ((CCV_CLI_VERBOSE & ccv_cli_get_output_levels()))
{ printf("[cnnp_sequential_model_build] 1. %p, sequence_size: %d\n"
, self, self->sequence_size); fflush(stdout); } } while (0
)
;
49 ccv_cnnp_model_t* const sub_model = self->sequence[0];
50 // Go through each sub model to build the graph.
51 ccv_nnc_tensor_symbol_t input;
52 sub_model->data = self->super.data;
53 ccv_cnnp_model_build(sub_model, graph, inputs, input_size, &input, 1);
54 sub_model->data = 0;
55 int i;
56 for (i = 1; i < self->sequence_size; i++)
57 {
58 ccv_nnc_tensor_symbol_t output;
59 ccv_cnnp_model_t* const sub_model = self->sequence[i];
60 // Go through each sub model to build the graph.
61 sub_model->data = self->super.data;
62 ccv_cnnp_model_build(sub_model, graph, &input, 1, &output, 1);
63 sub_model->data = 0;
64 input = output;
65 }
66 outputs[0] = input;
67 PRINT(CCV_CLI_VERBOSE, "[cnnp_sequential_model_build] 2. %p\n", self)do { if ((CCV_CLI_VERBOSE & ccv_cli_get_output_levels()))
{ printf("[cnnp_sequential_model_build] 2. %p\n", self); fflush
(stdout); } } while (0)
;
68}
69
70static void _ccv_cnnp_sequential_model_init_states(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_cnnp_state_initializer_f initializer, void* const context)
71{
72 ccv_cnnp_sequential_model_t* const self = (ccv_cnnp_sequential_model_t*)super;
73 int i;
74 for (i = 0; i < self->sequence_size; i++)
75 ccv_cnnp_model_init_states(self->sequence[i], graph, initializer, context);
76}
77
78static void _ccv_cnnp_sequential_model_set_is_test(ccv_cnnp_model_t* const super, const int is_test, const ccv_cnnp_cmd_updater_f updater, void* const context)
79{
80 ccv_cnnp_sequential_model_t* const self = (ccv_cnnp_sequential_model_t*)super;
81 int i;
82 for (i = 0; i < self->sequence_size; i++)
83 ccv_cnnp_model_set_is_test(self->sequence[i], is_test, updater, context);
84}
85
86static ccv_cnnp_model_t* _ccv_cnnp_sequential_model_copy(const ccv_cnnp_model_t* const super, void* const context);
87
88static void _ccv_cnnp_sequential_model_add_to_parameter_indices(ccv_cnnp_model_t* const super, const int index, ccv_array_t* const parameter_indices)
89{
90 ccv_cnnp_sequential_model_t* const self = (ccv_cnnp_sequential_model_t*)super;
91 int i;
92 for (i = 0; i < self->sequence_size; i++)
93 ccv_cnnp_model_add_to_parameter_indices(self->sequence[i], index, parameter_indices);
94}
95
96static void _ccv_cnnp_sequential_model_notify(const ccv_cnnp_model_t* const super, const int tag, void* const payload)
97{
98 ccv_cnnp_sequential_model_t* const self = (ccv_cnnp_sequential_model_t*)super;
99 int i;
100 for (i = 0; i < self->sequence_size; i++)
101 ccv_cnnp_model_notify(self->sequence[i], tag, payload);
102}
103
104static const ccv_cnnp_model_vtab_t ccv_cnnp_sequential_model_isa = {
105 .deinit = _ccv_cnnp_sequential_model_deinit,
106 .dealloc = _ccv_cnnp_sequential_model_dealloc,
107 .build = _ccv_cnnp_sequential_model_build,
108 .init_states = _ccv_cnnp_sequential_model_init_states,
109 .copy = _ccv_cnnp_sequential_model_copy,
110 .set_is_test = _ccv_cnnp_sequential_model_set_is_test,
111 .add_to_parameter_indices = _ccv_cnnp_sequential_model_add_to_parameter_indices,
112 .notify = _ccv_cnnp_sequential_model_notify,
113};
114
115KHASH_MAP_INIT_INT64(model, ccv_cnnp_model_t*)typedef struct kh_model_s { khint_t n_buckets, size, n_occupied
, upper_bound; khint32_t *flags; khint64_t *keys; ccv_cnnp_model_t
* *vals; } kh_model_t; static inline __attribute__ ((__unused__
)) kh_model_t *kh_init_model(void) { return (kh_model_t*)calloc
(1,sizeof(kh_model_t)); } static inline __attribute__ ((__unused__
)) void kh_destroy_model(kh_model_t *h) { if (h) { free((void
*)h->keys); free(h->flags); free((void *)h->vals); free
(h); } } static inline __attribute__ ((__unused__)) void kh_clear_model
(kh_model_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_model
(const kh_model_t *h, khint64_t key) { if (h->n_buckets) {
khint_t k, i, last, mask, step = 0; mask = h->n_buckets -
1; k = (khint32_t)((key)>>33^(key)^(key)<<11); i
= k & mask; last = i; while (!((h->flags[i>>4]>>
((i&0xfU)<<1))&2) && (((h->flags[i>>
4]>>((i&0xfU)<<1))&1) || !((h->keys[i]
) == (key)))) { 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_model
(kh_model_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) { khint64_t *new_keys
= (khint64_t*)realloc((void *)h->keys,new_n_buckets * sizeof
(khint64_t)); if (!new_keys) { free(new_flags); return -1; } h
->keys = new_keys; if (1) { ccv_cnnp_model_t* *new_vals = (
ccv_cnnp_model_t**)realloc((void *)h->vals,new_n_buckets *
sizeof(ccv_cnnp_model_t*)); 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) { khint64_t key
= h->keys[j]; ccv_cnnp_model_t* 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 = (khint32_t)((key)>>33^(key
)^(key)<<11); 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) { { khint64_t tmp = h->keys[i]; h->keys[i] = key
; key = tmp; } if (1) { ccv_cnnp_model_t* 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 = (khint64_t*)realloc((void
*)h->keys,new_n_buckets * sizeof(khint64_t)); if (1) h->
vals = (ccv_cnnp_model_t**)realloc((void *)h->vals,new_n_buckets
* sizeof(ccv_cnnp_model_t*)); } 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_model(kh_model_t *h, khint64_t
key, int *ret) { khint_t x; if (h->n_occupied >= h->
upper_bound) { if (h->n_buckets > (h->size<<1)
) { if (kh_resize_model(h, h->n_buckets - 1) < 0) { *ret
= -1; return h->n_buckets; } } else if (kh_resize_model(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 = (khint32_t)((key)>>
33^(key)^(key)<<11); 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) || !((h->keys[i]) ==
(key)))) { 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_model(kh_model_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; } }
116
117static ccv_cnnp_model_t* _ccv_cnnp_sequential_model_copy(const ccv_cnnp_model_t* const super, void* const context)
118{
119 const ccv_cnnp_sequential_model_t* const self = (const ccv_cnnp_sequential_model_t*)super;
120 ccv_cnnp_sequential_model_t* const sequential_model = (ccv_cnnp_sequential_model_t*)cccalloccalloc(1, sizeof(ccv_cnnp_sequential_model_t) + sizeof(ccv_cnnp_model_t*) * (self->sequence_size - 1) + sizeof(ccv_nnc_tensor_symbol_t));
121 sequential_model->super.isa = &ccv_cnnp_sequential_model_isa;
122 sequential_model->super.input_size = 1;
123 sequential_model->super.outputs = (ccv_nnc_tensor_symbol_t*)(sequential_model->sequence + self->sequence_size);
124 sequential_model->super.output_size = 1;
125 ccv_cnnp_model_copy_name(&sequential_model->super, self->super.name);
126 sequential_model->sequence_size = self->sequence_size;
127 int i;
128 khash_t(model)kh_model_t* model_map = context ? (khash_t(model)kh_model_t*)context : kh_init(model)kh_init_model();
129 for (i = 0; i < self->sequence_size; i++)
130 {
131 ccv_cnnp_model_t* const sub_model = self->sequence[i];
132 int ret;
133 khiter_t k = kh_put(model, model_map, (uint64_t)(uintptr_t)sub_model, &ret)kh_put_model(model_map, (uint64_t)(uintptr_t)sub_model, &
ret)
;
134 ccv_cnnp_model_t* model_copy;
135 if (ret != 0)
136 model_copy = kh_val(model_map, k)((model_map)->vals[k]) = _ccv_cnnp_model_copy(sub_model, model_map);
137 else
138 model_copy = kh_val(model_map, k)((model_map)->vals[k]);
139 sequential_model->sequence[i] = model_copy;
140 }
141 if (!context)
142 kh_destroy(model, model_map)kh_destroy_model(model_map);
143 return (ccv_cnnp_model_t*)sequential_model;
144}
145
146ccv_cnnp_model_t* ccv_cnnp_sequential_new(ccv_cnnp_model_t* const* const models, const int model_size, const int is_trainable, const char* const name)
147{
148 assert(model_size > 0)((void) sizeof ((model_size > 0) ? 1 : 0), __extension__ (
{ if (model_size > 0) ; else __assert_fail ("model_size > 0"
, "ccv_cnnp_model_core.c", 148, __extension__ __PRETTY_FUNCTION__
); }))
;
149 ccv_cnnp_sequential_model_t* const sequential_model = (ccv_cnnp_sequential_model_t*)cccalloccalloc(1, sizeof(ccv_cnnp_sequential_model_t) + sizeof(ccv_cnnp_model_t*) * (model_size - 1) + sizeof(ccv_nnc_tensor_symbol_t));
150 sequential_model->super.isa = &ccv_cnnp_sequential_model_isa;
151 sequential_model->super.input_size = models[0]->input_size;
152 sequential_model->super.outputs = (ccv_nnc_tensor_symbol_t*)(sequential_model->sequence + model_size);
153 sequential_model->super.output_size = 1;
154 sequential_model->super.is_trainable = is_trainable;
155 ccv_cnnp_model_copy_name(&sequential_model->super, name);
156 sequential_model->sequence_size = model_size;
157 memcpy(sequential_model->sequence, models, sizeof(ccv_cnnp_model_t*) * model_size);
158 return (ccv_cnnp_model_t*)sequential_model;
159}
160
161typedef struct {
162 ccv_cnnp_model_t super;
163 ccv_cnnp_model_t* model;
164 int count;
165 ccv_nnc_tensor_symbol_t outputs[1];
166} ccv_cnnp_replicated_model_t;
167
168static void _ccv_cnnp_replicated_model_deinit(ccv_cnnp_model_t* const super)
169{
170 ccv_cnnp_replicated_model_t* const self = (ccv_cnnp_replicated_model_t*)super;
171 if (self->model && !self->model->deinit_state)
172 ccv_cnnp_model_deinit(self->model);
173}
174
175static void _ccv_cnnp_replicated_model_dealloc(ccv_cnnp_model_t* const super)
176{
177 ccv_cnnp_replicated_model_t* const self = (ccv_cnnp_replicated_model_t*)super;
178 if (self->model)
179 ccv_cnnp_model_free(self->model);
180}
181
182static void _ccv_cnnp_replicated_model_build(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_nnc_tensor_symbol_t* const inputs, const int input_size, ccv_nnc_tensor_symbol_t* const outputs, const int output_size)
183{
184 ccv_cnnp_replicated_model_t* const self = (ccv_cnnp_replicated_model_t*)super;
185 ccv_cnnp_model_t* const model = self->model;
186 const int count = self->count;
187 assert(count > 1)((void) sizeof ((count > 1) ? 1 : 0), __extension__ ({ if (
count > 1) ; else __assert_fail ("count > 1", "ccv_cnnp_model_core.c"
, 187, __extension__ __PRETTY_FUNCTION__); }))
;
188 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_core.c", 188, __extension__ __PRETTY_FUNCTION__
); }))
;
189 assert(model->output_size > 0)((void) sizeof ((model->output_size > 0) ? 1 : 0), __extension__
({ if (model->output_size > 0) ; else __assert_fail ("model->output_size > 0"
, "ccv_cnnp_model_core.c", 189, __extension__ __PRETTY_FUNCTION__
); }))
;
190 assert(input_size == model->input_size * count)((void) sizeof ((input_size == model->input_size * count) ?
1 : 0), __extension__ ({ if (input_size == model->input_size
* count) ; else __assert_fail ("input_size == model->input_size * count"
, "ccv_cnnp_model_core.c", 190, __extension__ __PRETTY_FUNCTION__
); }))
;
191 assert(output_size == model->output_size * count)((void) sizeof ((output_size == model->output_size * count
) ? 1 : 0), __extension__ ({ if (output_size == model->output_size
* count) ; else __assert_fail ("output_size == model->output_size * count"
, "ccv_cnnp_model_core.c", 191, __extension__ __PRETTY_FUNCTION__
); }))
;
192 assert(super->data)((void) sizeof ((super->data) ? 1 : 0), __extension__ ({ if
(super->data) ; else __assert_fail ("super->data", "ccv_cnnp_model_core.c"
, 192, __extension__ __PRETTY_FUNCTION__); }))
;
193 ccv_cnnp_model_build_data_t* const build_data = (ccv_cnnp_model_build_data_t*)super->data;
194 const int old_parallel_count = build_data->parallel_count;
195 const int old_parallel_rank = build_data->parallel_rank;
196 assert(old_parallel_count <= 1)((void) sizeof ((old_parallel_count <= 1) ? 1 : 0), __extension__
({ if (old_parallel_count <= 1) ; else __assert_fail ("old_parallel_count <= 1"
, "ccv_cnnp_model_core.c", 196, __extension__ __PRETTY_FUNCTION__
); }))
;
197 int i;
198 for (i = 0; i < count; i++)
199 {
200 build_data->parallel_count = count;
201 build_data->parallel_rank = i;
202 void* const old_data = model->data;
203 model->data = super->data;
204 ccv_cnnp_model_build(model, graph, inputs + i * model->input_size, model->input_size, outputs + i * model->output_size, model->output_size);
205 model->data = old_data;
206 }
207 build_data->parallel_count = old_parallel_count;
208 build_data->parallel_rank = old_parallel_rank;
209}
210
211static void _ccv_cnnp_replicated_model_init_states(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_cnnp_state_initializer_f initializer, void* const context)
212{
213 ccv_cnnp_replicated_model_t* const self = (ccv_cnnp_replicated_model_t*)super;
214 ccv_cnnp_model_init_states(self->model, graph, initializer, context);
215}
216
217static void _ccv_cnnp_replicated_model_set_is_test(ccv_cnnp_model_t* const super, const int is_test, const ccv_cnnp_cmd_updater_f updater, void* const context)
218{
219 ccv_cnnp_replicated_model_t* const self = (ccv_cnnp_replicated_model_t*)super;
220 ccv_cnnp_model_set_is_test(self->model, is_test, updater, context);
221}
222
223static void _ccv_cnnp_replicated_model_add_to_parameter_indices(ccv_cnnp_model_t* const super, const int index, ccv_array_t* const parameter_indices)
224{
225 ccv_cnnp_replicated_model_t* const self = (ccv_cnnp_replicated_model_t*)super;
226 ccv_cnnp_model_add_to_parameter_indices(self->model, index, parameter_indices);
227}
228
229static void _ccv_cnnp_replicated_model_notify(const ccv_cnnp_model_t* const super, const int tag, void* const payload)
230{
231 ccv_cnnp_replicated_model_t* const self = (ccv_cnnp_replicated_model_t*)super;
232 ccv_cnnp_model_notify(self->model, tag, payload);
233}
234
235static ccv_cnnp_model_t* _ccv_cnnp_replicated_model_copy(const ccv_cnnp_model_t* const super, void* const context);
236
237static const ccv_cnnp_model_vtab_t ccv_cnnp_replicated_model_isa = {
238 .deinit = _ccv_cnnp_replicated_model_deinit,
239 .dealloc = _ccv_cnnp_replicated_model_dealloc,
240 .build = _ccv_cnnp_replicated_model_build,
241 .init_states = _ccv_cnnp_replicated_model_init_states,
242 .copy = _ccv_cnnp_replicated_model_copy,
243 .set_is_test = _ccv_cnnp_replicated_model_set_is_test,
244 .add_to_parameter_indices = _ccv_cnnp_replicated_model_add_to_parameter_indices,
245 .notify = _ccv_cnnp_replicated_model_notify,
246};
247
248ccv_cnnp_model_t* ccv_cnnp_replicated(ccv_cnnp_model_t* const model, const int count, const char* const name)
249{
250 assert(model)((void) sizeof ((model) ? 1 : 0), __extension__ ({ if (model)
; else __assert_fail ("model", "ccv_cnnp_model_core.c", 250,
__extension__ __PRETTY_FUNCTION__); }))
;
251 assert(count > 1)((void) sizeof ((count > 1) ? 1 : 0), __extension__ ({ if (
count > 1) ; else __assert_fail ("count > 1", "ccv_cnnp_model_core.c"
, 251, __extension__ __PRETTY_FUNCTION__); }))
;
252 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_core.c", 252, __extension__ __PRETTY_FUNCTION__
); }))
;
253 assert(model->output_size > 0)((void) sizeof ((model->output_size > 0) ? 1 : 0), __extension__
({ if (model->output_size > 0) ; else __assert_fail ("model->output_size > 0"
, "ccv_cnnp_model_core.c", 253, __extension__ __PRETTY_FUNCTION__
); }))
;
254 const int output_size = model->output_size * count;
255 ccv_cnnp_replicated_model_t* const replicated_model = (ccv_cnnp_replicated_model_t*)cccalloccalloc(1, sizeof(ccv_cnnp_replicated_model_t) + sizeof(ccv_nnc_tensor_symbol_t) * (output_size - 1));
256 replicated_model->super.isa = &ccv_cnnp_replicated_model_isa;
257 replicated_model->super.input_size = model->input_size * count;
258 replicated_model->super.outputs = replicated_model->outputs;
259 replicated_model->super.output_size = output_size;
260 replicated_model->super.is_trainable = -1;
261 ccv_cnnp_model_copy_name(&replicated_model->super, name);
262 replicated_model->model = model;
263 replicated_model->count = count;
264 return (ccv_cnnp_model_t*)replicated_model;
265}
266
267static ccv_cnnp_model_t* _ccv_cnnp_replicated_model_copy(const ccv_cnnp_model_t* const super, void* const context)
268{
269 const ccv_cnnp_replicated_model_t* const self = (const ccv_cnnp_replicated_model_t*)super;
270 ccv_cnnp_model_t* const model_copy = _ccv_cnnp_model_copy(self->model, context);
271 return ccv_cnnp_replicated(model_copy, self->count, self->super.name);
272}
273
274typedef struct {
275 ccv_cnnp_model_t super;
276 // The model's outputs, it is different from super.output_size, as latter is for actual tensor symbols.
277 int model_output_size;
278 // The name is similar to sequential model, but it is just topological sorted models.
279 int sequence_size;
280 int* model_outputs; // Which model, as in sequences, have some outputs.
281 ccv_cnnp_model_io_t sequence[1];
282} ccv_cnnp_functional_model_t;
283
284static void _ccv_cnnp_functional_model_deinit(ccv_cnnp_model_t* const super)
285{
286 ccv_cnnp_functional_model_t* const self = (ccv_cnnp_functional_model_t*)super;
287 int i, j = 0, k;
288 for (i = 0; i < self->sequence_size; i++)
289 {
290 ccv_cnnp_model_t* const model = self->sequence[i]->model;
291 if (!model || model->deinit_state)
292 continue;
293 self->sequence[j++] = (ccv_cnnp_model_io_t)model;
294 // Go through all their IO to remove itself as model.
295 assert(model->io)((void) sizeof ((model->io) ? 1 : 0), __extension__ ({ if (
model->io) ; else __assert_fail ("model->io", "ccv_cnnp_model_core.c"
, 295, __extension__ __PRETTY_FUNCTION__); }))
;
296 for (k = 0; k < model->io->rnum; k++)
297 {
298 ccv_cnnp_model_io_t model_io = *(ccv_cnnp_model_io_t*)ccv_array_get(model->io, k)((void*)(((char*)((model->io)->data)) + (size_t)(model->
io)->rsize * (size_t)(k)))
;
299 model_io->model = 0;
300 }
301 }
302 for (i = 0; i < j; i++)
303 ccv_cnnp_model_deinit((ccv_cnnp_model_t*)self->sequence[i]);
304 self->sequence_size = j;
305}
306
307static void _ccv_cnnp_functional_model_dealloc(ccv_cnnp_model_t* const super)
308{
309 ccv_cnnp_functional_model_t* const self = (ccv_cnnp_functional_model_t*)super;
310 int i;
311 for (i = 0; i < self->sequence_size; i++)
312 ccv_cnnp_model_free((ccv_cnnp_model_t*)self->sequence[i]);
313}
314
315KHASH_MAP_INIT_INT64(io_node, ccv_array_t*)typedef struct kh_io_node_s { khint_t n_buckets, size, n_occupied
, upper_bound; khint32_t *flags; khint64_t *keys; ccv_array_t
* *vals; } kh_io_node_t; static inline __attribute__ ((__unused__
)) kh_io_node_t *kh_init_io_node(void) { return (kh_io_node_t
*)calloc(1,sizeof(kh_io_node_t)); } static inline __attribute__
((__unused__)) void kh_destroy_io_node(kh_io_node_t *h) { if
(h) { free((void *)h->keys); free(h->flags); free((void
*)h->vals); free(h); } } static inline __attribute__ ((__unused__
)) void kh_clear_io_node(kh_io_node_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_io_node(const kh_io_node_t *h, khint64_t
key) { if (h->n_buckets) { khint_t k, i, last, mask, step
= 0; mask = h->n_buckets - 1; k = (khint32_t)((key)>>
33^(key)^(key)<<11); i = k & mask; last = i; while (
!((h->flags[i>>4]>>((i&0xfU)<<1))&
2) && (((h->flags[i>>4]>>((i&0xfU)
<<1))&1) || !((h->keys[i]) == (key)))) { 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_io_node(kh_io_node_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) { khint64_t *new_keys
= (khint64_t*)realloc((void *)h->keys,new_n_buckets * sizeof
(khint64_t)); if (!new_keys) { free(new_flags); return -1; } h
->keys = new_keys; if (1) { ccv_array_t* *new_vals = (ccv_array_t
**)realloc((void *)h->vals,new_n_buckets * sizeof(ccv_array_t
*)); 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) { khint64_t key = h->keys[j]; ccv_array_t
* 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
= (khint32_t)((key)>>33^(key)^(key)<<11); 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) { { khint64_t tmp = h->
keys[i]; h->keys[i] = key; key = tmp; } if (1) { ccv_array_t
* 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 = (
khint64_t*)realloc((void *)h->keys,new_n_buckets * sizeof(
khint64_t)); if (1) h->vals = (ccv_array_t**)realloc((void
*)h->vals,new_n_buckets * sizeof(ccv_array_t*)); } 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_io_node(kh_io_node_t
*h, khint64_t key, int *ret) { khint_t x; if (h->n_occupied
>= h->upper_bound) { if (h->n_buckets > (h->size
<<1)) { if (kh_resize_io_node(h, h->n_buckets - 1) <
0) { *ret = -1; return h->n_buckets; } } else if (kh_resize_io_node
(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 = (khint32_t)((key)>>
33^(key)^(key)<<11); 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) || !((h->keys[i]) ==
(key)))) { 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_io_node(kh_io_node_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; } }
316
317typedef struct {
318 ccv_array_t* nodes;
319 ccv_nnc_graph_exec_symbol_new_hook_f previous_func;
320 void* previous_context;
321} ccv_functional_model_build_node_hook_t;
322
323static void _ccv_cnnp_functional_model_build_node_new(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)
324{
325 ccv_functional_model_build_node_hook_t* const hook = (ccv_functional_model_build_node_hook_t*)context;
326 ccv_array_push(hook->nodes, &symbol);
327 if (hook->previous_func)
328 hook->previous_func(hook->previous_context, symbol, cmd, inputs, input_size, outputs, output_size, name);
329}
330
331static void _ccv_cnnp_functional_model_build(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_nnc_tensor_symbol_t* const inputs, const int input_size, ccv_nnc_tensor_symbol_t* const outputs, const int output_size)
332{
333 ccv_cnnp_functional_model_t* const self = (ccv_cnnp_functional_model_t*)super;
334 PRINT(CCV_CLI_VERBOSE, "[cnnp_functional_model_build] 1. %p, input_size: %d, output_size: %d\n", self, input_size, output_size)do { if ((CCV_CLI_VERBOSE & ccv_cli_get_output_levels()))
{ printf("[cnnp_functional_model_build] 1. %p, input_size: %d, output_size: %d\n"
, self, input_size, output_size); fflush(stdout); } } while (
0)
;
335 assert(self->super.input_size == input_size)((void) sizeof ((self->super.input_size == input_size) ? 1
: 0), __extension__ ({ if (self->super.input_size == input_size
) ; else __assert_fail ("self->super.input_size == input_size"
, "ccv_cnnp_model_core.c", 335, __extension__ __PRETTY_FUNCTION__
); }))
;
336 assert(self->super.output_size == output_size)((void) sizeof ((self->super.output_size == output_size) ?
1 : 0), __extension__ ({ if (self->super.output_size == output_size
) ; else __assert_fail ("self->super.output_size == output_size"
, "ccv_cnnp_model_core.c", 336, __extension__ __PRETTY_FUNCTION__
); }))
;
337 int i, j, k;
338 for (i = 0; i < self->super.input_size; i++)
339 self->sequence[i]->outputs[0] = self->sequence[i]->model->outputs[0] = inputs[i]; // Assigning the output symbol of input layer to be the input symbol.
340 ccv_array_t* input_symbols = ccv_array_new(sizeof(ccv_nnc_tensor_symbol_t), 1, 0);
341 ccv_array_t* parameter_indices = 0;
342 khash_t(io_node)kh_io_node_t* io_node_map = kh_init(io_node)kh_init_io_node();
343 for (i = self->super.input_size; i < self->sequence_size; i++)
344 {
345 ccv_cnnp_model_t* const sub_model = self->sequence[i]->model;
346 ccv_array_clear(input_symbols);
347 const ccv_array_t* const incomings = self->sequence[i]->incomings;
348 if (incomings)
349 for (j = 0; j < incomings->rnum; j++)
350 {
351 const ccv_cnnp_model_io_t input = *(ccv_cnnp_model_io_t*)ccv_array_get(incomings, j)((void*)(((char*)((incomings)->data)) + (size_t)(incomings
)->rsize * (size_t)(j)))
;
352 if (CCV_CNNP_IS_MODEL_PARAMETER(input)((input)->param_ref != 0 || (input)->param_sel != 0))
353 {
354 if (!parameter_indices)
355 parameter_indices = ccv_array_new(sizeof(int), 0, 0);
356 else
357 ccv_array_clear(parameter_indices);
358 const int param_sel = input->param_sel > 0 ? input->param_sel - 1 : input->param_sel;
359 assert(input->param_sel != 0)((void) sizeof ((input->param_sel != 0) ? 1 : 0), __extension__
({ if (input->param_sel != 0) ; else __assert_fail ("input->param_sel != 0"
, "ccv_cnnp_model_core.c", 359, __extension__ __PRETTY_FUNCTION__
); }))
;
360 ccv_cnnp_model_add_to_parameter_indices(input->model, param_sel, parameter_indices);
361 assert(parameter_indices->rnum > 0)((void) sizeof ((parameter_indices->rnum > 0) ? 1 : 0),
__extension__ ({ if (parameter_indices->rnum > 0) ; else
__assert_fail ("parameter_indices->rnum > 0", "ccv_cnnp_model_core.c"
, 361, __extension__ __PRETTY_FUNCTION__); }))
;
362 const int param_ref = input->param_ref > 0 ? input->param_ref - 1 : input->param_ref;
363 assert(input->param_ref != 0)((void) sizeof ((input->param_ref != 0) ? 1 : 0), __extension__
({ if (input->param_ref != 0) ; else __assert_fail ("input->param_ref != 0"
, "ccv_cnnp_model_core.c", 363, __extension__ __PRETTY_FUNCTION__
); }))
;
364 if (param_ref >= 0)
365 {
366 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_core.c", 366, __extension__ __PRETTY_FUNCTION__
); }))
;
367 const ccv_nnc_tensor_symbol_t parameter = ccv_cnnp_parameter_from_indice(super, *(int*)ccv_array_get(parameter_indices, param_ref)((void*)(((char*)((parameter_indices)->data)) + (size_t)(parameter_indices
)->rsize * (size_t)(param_ref)))
);
368 ccv_array_push(input_symbols, &parameter);
369 } else // Otherwise, all of them.
370 for (k = 0; k < parameter_indices->rnum; k++)
371 {
372 const ccv_nnc_tensor_symbol_t parameter = ccv_cnnp_parameter_from_indice(super, *(int*)ccv_array_get(parameter_indices, k)((void*)(((char*)((parameter_indices)->data)) + (size_t)(parameter_indices
)->rsize * (size_t)(k)))
);
373 ccv_array_push(input_symbols, &parameter);
374 }
375 } else {
376 for (k = 0; k < input->model->output_size; k++)
377 ccv_array_push(input_symbols, &input->outputs[k]);
378 }
379 }
380 // Go through each sub model to build the graph.
381 ccv_array_t* nodes;
382 ccv_functional_model_build_node_hook_t hook;
383 const ccv_array_t* const dependencies = self->sequence[i]->dependencies;
384 if ((dependencies && dependencies->rnum > 0) || self->sequence[i]->dependents > 0)
385 {
386 int ret;
387 khiter_t k = kh_put(io_node, io_node_map, (uint64_t)(uintptr_t)self->sequence[i], &ret)kh_put_io_node(io_node_map, (uint64_t)(uintptr_t)self->sequence
[i], &ret)
;
388 if (ret != 0)
389 nodes = kh_val(io_node_map, k)((io_node_map)->vals[k]) = ccv_array_new(sizeof(ccv_nnc_graph_exec_symbol_t), 1, 0);
390 else
391 nodes = kh_val(io_node_map, k)((io_node_map)->vals[k]);
392 hook.nodes = nodes;
393 hook.previous_context = ccv_nnc_graph_exec_symbol_new_hook(graph, _ccv_cnnp_functional_model_build_node_new, &hook, &hook.previous_func);
394 }
395 sub_model->data = self->super.data;
396 ccv_cnnp_model_build(sub_model, graph, (ccv_nnc_tensor_symbol_t*)ccv_array_get(input_symbols, 0)((void*)(((char*)((input_symbols)->data)) + (size_t)(input_symbols
)->rsize * (size_t)(0)))
, input_symbols->rnum, self->sequence[i]->outputs, sub_model->output_size);
397 if ((dependencies && dependencies->rnum > 0) || self->sequence[i]->dependents > 0)
398 {
399 ccv_nnc_graph_exec_symbol_new_hook(graph, hook.previous_func, hook.previous_context, 0);
400 if (dependencies)
401 for (j = 0; j < dependencies->rnum; j++)
402 {
403 const ccv_cnnp_model_io_t dependency = *(ccv_cnnp_model_io_t*)ccv_array_get(dependencies, j)((void*)(((char*)((dependencies)->data)) + (size_t)(dependencies
)->rsize * (size_t)(j)))
;
404 khiter_t k = kh_get(io_node, io_node_map, (uint64_t)(uintptr_t)dependency)kh_get_io_node(io_node_map, (uint64_t)(uintptr_t)dependency);
405 if (k == kh_end(io_node_map)((io_node_map)->n_buckets))
406 continue;
407 const ccv_array_t* const dependency_nodes = kh_val(io_node_map, k)((io_node_map)->vals[k]);
408 int x, y;
409 for (y = 0; y < dependency_nodes->rnum; y++)
410 for (x = 0; x < nodes->rnum; x++)
411 ccv_nnc_graph_exec_symbol_concat(graph, *(ccv_nnc_graph_exec_symbol_t*)ccv_array_get(dependency_nodes, y)((void*)(((char*)((dependency_nodes)->data)) + (size_t)(dependency_nodes
)->rsize * (size_t)(y)))
, *(ccv_nnc_graph_exec_symbol_t*)ccv_array_get(nodes, x)((void*)(((char*)((nodes)->data)) + (size_t)(nodes)->rsize
* (size_t)(x)))
);
412 }
413 }
414 sub_model->data = 0;
415 }
416 khiter_t it;
417 for (it = kh_begin(io_node_map)(khint_t)(0); it != kh_end(io_node_map)((io_node_map)->n_buckets); ++it)
418 {
419 if (!kh_exist(io_node_map, it)(!(((io_node_map)->flags[(it)>>4]>>(((it)&
0xfU)<<1))&3))
)
420 continue;
421 ccv_array_t* const nodes = kh_val(io_node_map, it)((io_node_map)->vals[it]);
422 ccv_array_free(nodes);
423 }
424 kh_destroy(io_node, io_node_map)kh_destroy_io_node(io_node_map);
425 ccv_array_free(input_symbols);
426 if (parameter_indices)
427 ccv_array_free(parameter_indices);
428 for (i = 0, k = 0; k < self->model_output_size; k++)
429 {
430 ccv_cnnp_model_t* const sub_model = self->sequence[self->model_outputs[k]]->model;
431 for (j = 0; j < sub_model->output_size; j++)
432 outputs[i + j] = self->sequence[self->model_outputs[k]]->outputs[j];
433 i += sub_model->output_size;
434 }
435 assert(i == output_size)((void) sizeof ((i == output_size) ? 1 : 0), __extension__ ({
if (i == output_size) ; else __assert_fail ("i == output_size"
, "ccv_cnnp_model_core.c", 435, __extension__ __PRETTY_FUNCTION__
); }))
;
436 PRINT(CCV_CLI_VERBOSE, "[cnnp_functional_model_build] 2. %p\n", self)do { if ((CCV_CLI_VERBOSE & ccv_cli_get_output_levels()))
{ printf("[cnnp_functional_model_build] 2. %p\n", self); fflush
(stdout); } } while (0)
;
437}
438
439static void _ccv_cnnp_functional_model_init_states(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_cnnp_state_initializer_f initializer, void* const context)
440{
441 ccv_cnnp_functional_model_t* const self = (ccv_cnnp_functional_model_t*)super;
442 int i;
443 for (i = self->super.input_size; i < self->sequence_size; i++)
444 ccv_cnnp_model_init_states(self->sequence[i]->model, graph, initializer, context);
445}
446
447static void _ccv_cnnp_functional_model_set_is_test(ccv_cnnp_model_t* const super, const int is_test, const ccv_cnnp_cmd_updater_f updater, void* const context)
448{
449 ccv_cnnp_functional_model_t* const self = (ccv_cnnp_functional_model_t*)super;
450 int i;
451 for (i = self->super.input_size; i < self->sequence_size; i++)
452 ccv_cnnp_model_set_is_test(self->sequence[i]->model, is_test, updater, context);
453}
454
455static void _ccv_cnnp_functional_model_add_to_parameter_indices(ccv_cnnp_model_t* const super, const int index, ccv_array_t* const parameter_indices)
456{
457 ccv_cnnp_functional_model_t* const self = (ccv_cnnp_functional_model_t*)super;
458 int i;
459 for (i = self->super.input_size; i < self->sequence_size; i++)
460 ccv_cnnp_model_add_to_parameter_indices(self->sequence[i]->model, index, parameter_indices);
461}
462
463static void _ccv_cnnp_functional_model_notify(const ccv_cnnp_model_t* const super, const int tag, void* const payload)
464{
465 ccv_cnnp_functional_model_t* const self = (ccv_cnnp_functional_model_t*)super;
466 int i;
467 for (i = 0; i < self->sequence_size; i++)
468 {
469 const ccv_cnnp_model_t* const model = self->sequence[i]->model;
470 ccv_cnnp_model_notify(model, tag, payload);
471 }
472}
473
474static ccv_cnnp_model_t* _ccv_cnnp_functional_model_copy(const ccv_cnnp_model_t* const super, void* const context);
475
476static const ccv_cnnp_model_vtab_t ccv_cnnp_functional_model_isa = {
477 .deinit = _ccv_cnnp_functional_model_deinit,
478 .dealloc = _ccv_cnnp_functional_model_dealloc,
479 .build = _ccv_cnnp_functional_model_build,
480 .init_states = _ccv_cnnp_functional_model_init_states,
481 .copy = _ccv_cnnp_functional_model_copy,
482 .set_is_test = _ccv_cnnp_functional_model_set_is_test,
483 .add_to_parameter_indices = _ccv_cnnp_functional_model_add_to_parameter_indices,
484 .notify = _ccv_cnnp_functional_model_notify,
485};
486
487KHASH_MAP_INIT_INT64(model_io, ccv_cnnp_model_io_t)typedef struct kh_model_io_s { khint_t n_buckets, size, n_occupied
, upper_bound; khint32_t *flags; khint64_t *keys; ccv_cnnp_model_io_t
*vals; } kh_model_io_t; static inline __attribute__ ((__unused__
)) kh_model_io_t *kh_init_model_io(void) { return (kh_model_io_t
*)calloc(1,sizeof(kh_model_io_t)); } static inline __attribute__
((__unused__)) void kh_destroy_model_io(kh_model_io_t *h) { if
(h) { free((void *)h->keys); free(h->flags); free((void
*)h->vals); free(h); } } static inline __attribute__ ((__unused__
)) void kh_clear_model_io(kh_model_io_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_model_io(const kh_model_io_t *h,
khint64_t key) { if (h->n_buckets) { khint_t k, i, last, mask
, step = 0; mask = h->n_buckets - 1; k = (khint32_t)((key)
>>33^(key)^(key)<<11); i = k & mask; last = i
; while (!((h->flags[i>>4]>>((i&0xfU)<<
1))&2) && (((h->flags[i>>4]>>((i&
0xfU)<<1))&1) || !((h->keys[i]) == (key)))) { 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_model_io(kh_model_io_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) { khint64_t *new_keys
= (khint64_t*)realloc((void *)h->keys,new_n_buckets * sizeof
(khint64_t)); if (!new_keys) { free(new_flags); return -1; } h
->keys = new_keys; if (1) { ccv_cnnp_model_io_t *new_vals =
(ccv_cnnp_model_io_t*)realloc((void *)h->vals,new_n_buckets
* sizeof(ccv_cnnp_model_io_t)); 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) { khint64_t key
= h->keys[j]; ccv_cnnp_model_io_t 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 = (khint32_t)((key)>>33^(key
)^(key)<<11); 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) { { khint64_t tmp = h->keys[i]; h->keys[i] = key
; key = tmp; } if (1) { ccv_cnnp_model_io_t 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 = (khint64_t*)realloc
((void *)h->keys,new_n_buckets * sizeof(khint64_t)); if (1
) h->vals = (ccv_cnnp_model_io_t*)realloc((void *)h->vals
,new_n_buckets * sizeof(ccv_cnnp_model_io_t)); } 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_model_io(
kh_model_io_t *h, khint64_t key, int *ret) { khint_t x; if (h
->n_occupied >= h->upper_bound) { if (h->n_buckets
> (h->size<<1)) { if (kh_resize_model_io(h, h->
n_buckets - 1) < 0) { *ret = -1; return h->n_buckets; }
} else if (kh_resize_model_io(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 = (khint32_t)((key)>>33^(key)^(key)<<
11); 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) || !((h->keys[i]) == (key)))) { 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_model_io(kh_model_io_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; } }
14
Taking true branch
15
Taking false branch
16
Calling 'kh_resize_model_io'
17
Taking true branch
18
Assuming the condition is false
19
Taking false branch
20
'?' condition is true
21
Assuming 'new_flags' is non-null
22
Taking false branch
23
'?' condition is true
24
Taking true branch
25
Storing uninitialized value
26
Assuming 'new_keys' is non-null
27
Taking false branch
28
Taking true branch
29
Assuming 'new_vals' is non-null
30
Taking false branch
31
Taking true branch
32
Loop condition is false. Execution continues on line 487
33
Taking false branch
34
Returning from 'kh_resize_model_io'
35
Taking false branch
36
Assuming right operand of bit shift is less than 32
37
Assuming the condition is true
38
Taking true branch
39
Assuming the condition is false
40
Taking false branch
41
Assuming the condition is false
42
Taking false branch
48
Assuming field 'n_occupied' is >= field 'upper_bound'
49
Taking true branch
50
Taking true branch
51
Calling 'kh_resize_model_io'
52
Taking false branch
53
Assuming the condition is false
54
Taking false branch
55
'?' condition is true
56
Assuming 'new_flags' is non-null
57
Taking false branch
58
'?' condition is true
59
Taking false branch
60
Taking true branch
61
The value 0 is assigned to 'j'
62
Loop condition is true. Entering loop body
63
Assuming the condition is true
64
Taking true branch
65
Assigned value is garbage or undefined
488
489static ccv_cnnp_model_t* _ccv_cnnp_functional_model_copy(const ccv_cnnp_model_t* const super, void* const context)
490{
491 const ccv_cnnp_functional_model_t* const self = (const ccv_cnnp_functional_model_t*)super;
492 ccv_cnnp_functional_model_t* const functional_model = (ccv_cnnp_functional_model_t*)cccalloccalloc(1, sizeof(ccv_cnnp_functional_model_t) + sizeof(ccv_cnnp_model_t*) * (self->sequence_size - 1) + sizeof(ccv_nnc_tensor_symbol_t) * self->super.output_size + sizeof(int) * self->model_output_size);
493 functional_model->super.isa = &ccv_cnnp_functional_model_isa;
494 functional_model->super.outputs = (ccv_nnc_tensor_symbol_t*)(functional_model->sequence + self->sequence_size);
495 functional_model->super.output_size = self->super.output_size;
496 functional_model->super.input_size = self->super.input_size;
497 ccv_cnnp_model_copy_name(&functional_model->super, self->super.name);
498 functional_model->sequence_size = self->sequence_size;
499 functional_model->model_output_size = self->model_output_size;
500 functional_model->model_outputs = (int*)(functional_model->super.outputs + functional_model->super.output_size);
501 memcpy(functional_model->model_outputs, self->model_outputs, sizeof(int) * self->model_output_size);
502 // Now the difficult part, copy over the model_io.
503 khash_t(model_io)kh_model_io_t* model_io_map = kh_init(model_io)kh_init_model_io();
504 khash_t(model)kh_model_t* model_map = context ? (khash_t(model)kh_model_t*)context : kh_init(model)kh_init_model();
1
Assuming 'context' is null
2
'?' condition is false
505 int i, j;
506 for (i = 0; i < self->sequence_size; i++)
3
Assuming 'i' is >= field 'sequence_size'
4
Loop condition is false. Execution continues on line 532
507 {
508 const ccv_cnnp_model_t* const sub_model = self->sequence[i]->model;
509 int ret;
510 khiter_t k = kh_put(model, model_map, (uint64_t)(uintptr_t)sub_model, &ret)kh_put_model(model_map, (uint64_t)(uintptr_t)sub_model, &
ret)
;
511 ccv_cnnp_model_t* model_copy;
512 if (ret != 0)
513 model_copy = kh_val(model_map, k)((model_map)->vals[k]) = _ccv_cnnp_model_copy(sub_model, model_map);
514 else
515 model_copy = kh_val(model_map, k)((model_map)->vals[k]);
516 ccv_cnnp_model_io_t model_io = functional_model->sequence[i] = ccmallocmalloc(sizeof(struct ccv_cnnp_model_io_s) + sizeof(ccv_nnc_tensor_symbol_t) * sub_model->output_size);
517 model_io->param_ref = 0;
518 model_io->param_sel = 0;
519 model_io->visit = 0;
520 model_io->model = model_copy;
521 model_io->dependencies = 0;
522 model_io->dependents = 0;
523 model_io->incomings = 0;
524 model_io->outgoings = 0;
525 model_io->outputs = (ccv_nnc_tensor_symbol_t*)(model_io + 1);
526 if (!model_copy->io)
527 model_copy->io = ccv_array_new(sizeof(ccv_cnnp_model_io_t), 1, 0);
528 ccv_array_push(model_copy->io, &model_io);
529 k = kh_put(model_io, model_io_map, (uint64_t)(uintptr_t)self->sequence[i], &ret)kh_put_model_io(model_io_map, (uint64_t)(uintptr_t)self->sequence
[i], &ret)
;
530 kh_val(model_io_map, k)((model_io_map)->vals[k]) = functional_model->sequence[i];
531 }
532 for (i = self->super.input_size; i < self->sequence_size; i++)
5
Assuming 'i' is < field 'sequence_size'
6
Loop condition is true. Entering loop body
533 {
534 if (self->sequence[i]->incomings)
7
Assuming field 'incomings' is non-null
8
Taking true branch
535 for (j = 0; j < self->sequence[i]->incomings->rnum; j++)
9
Loop condition is true. Entering loop body
45
Loop condition is true. Entering loop body
536 {
537 const ccv_cnnp_model_io_t input = *(ccv_cnnp_model_io_t*)ccv_array_get(self->sequence[i]->incomings, j)((void*)(((char*)((self->sequence[i]->incomings)->data
)) + (size_t)(self->sequence[i]->incomings)->rsize *
(size_t)(j)))
;
538 if (CCV_CNNP_IS_MODEL_PARAMETER(input)((input)->param_ref != 0 || (input)->param_sel != 0)) // I am pretty sure this is not in the model_io_map.
10
Assuming field 'param_ref' is equal to 0
11
Assuming field 'param_sel' is not equal to 0
12
Taking true branch
46
Assuming field 'param_ref' is not equal to 0
539 {
540 int ret;
541 khiter_t k = kh_put(model_io, model_io_map, (uint64_t)(uintptr_t)input, &ret)kh_put_model_io(model_io_map, (uint64_t)(uintptr_t)input, &
ret)
;
13
Calling 'kh_put_model_io'
43
Returning from 'kh_put_model_io'
47
Calling 'kh_put_model_io'
542 if (ret
43.1
'ret' is equal to 0
!= 0)
44
Taking false branch
543 {
544 // The model may not exist on the map due to wrapping (it is inside another sequential or functional model).
545 khiter_t m = kh_get(model, model_map, (uint64_t)(uintptr_t)input->model)kh_get_model(model_map, (uint64_t)(uintptr_t)input->model);
546 assert(m != kh_end(model_map))((void) sizeof ((m != ((model_map)->n_buckets)) ? 1 : 0), __extension__
({ if (m != ((model_map)->n_buckets)) ; else __assert_fail
("m != kh_end(model_map)", "ccv_cnnp_model_core.c", 546, __extension__
__PRETTY_FUNCTION__); }))
;
547 ccv_cnnp_model_t* const model_copy = kh_val(model_map, m)((model_map)->vals[m]);
548 ccv_cnnp_model_io_t model_io = ccmallocmalloc(sizeof(struct ccv_cnnp_model_io_s));
549 model_io->param_ref = input->param_ref;
550 model_io->param_sel = input->param_sel;
551 model_io->visit = 0;
552 model_io->model = model_copy;
553 model_io->incomings = 0;
554 model_io->dependencies = 0;
555 model_io->dependents = 0;
556 model_io->outgoings = 0;
557 model_io->outputs = 0;
558 if (!model_copy->io)
559 model_copy->io = ccv_array_new(sizeof(ccv_cnnp_model_io_t), 1, 0);
560 ccv_array_push(model_copy->io, &model_io);
561 kh_val(model_io_map, k)((model_io_map)->vals[k]) = model_io;
562 if (input->outgoings)
563 {
564 model_io->outgoings = ccv_array_new(sizeof(ccv_cnnp_model_io_t), input->outgoings->rnum, 0);
565 int x;
566 for (x = 0; x < input->outgoings->rnum; x++)
567 {
568 khiter_t k = kh_get(model_io, model_io_map, (uint64_t)(uintptr_t)(*(ccv_cnnp_model_io_t*)ccv_array_get(input->outgoings, x)))kh_get_model_io(model_io_map, (uint64_t)(uintptr_t)(*(ccv_cnnp_model_io_t
*)((void*)(((char*)((input->outgoings)->data)) + (size_t
)(input->outgoings)->rsize * (size_t)(x)))))
;
569 assert(k != kh_end(model_io_map))((void) sizeof ((k != ((model_io_map)->n_buckets)) ? 1 : 0
), __extension__ ({ if (k != ((model_io_map)->n_buckets)) ;
else __assert_fail ("k != kh_end(model_io_map)", "ccv_cnnp_model_core.c"
, 569, __extension__ __PRETTY_FUNCTION__); }))
;
570 ccv_cnnp_model_io_t outgoing_io = kh_val(model_io_map, k)((model_io_map)->vals[k]);
571 ccv_array_push(model_io->outgoings, &outgoing_io);
572 }
573 }
574 }
575 }
576 }
577 }
578 if (!context)
579 kh_destroy(model, model_map)kh_destroy_model(model_map);
580 for (i = 0; i < self->sequence_size; i++)
581 {
582 const ccv_cnnp_model_io_t model_io = self->sequence[i];
583 ccv_cnnp_model_io_t model_io_copy = functional_model->sequence[i];
584 model_io_copy->param_ref = model_io->param_ref;
585 model_io_copy->param_sel = model_io->param_sel;
586 if (model_io->incomings)
587 {
588 model_io_copy->incomings = ccv_array_new(sizeof(ccv_cnnp_model_io_t), model_io->incomings->rnum, 0);
589 for (j = 0; j < model_io->incomings->rnum; j++)
590 {
591 khiter_t k = kh_get(model_io, model_io_map, (uint64_t)(uintptr_t)(*(ccv_cnnp_model_io_t*)ccv_array_get(model_io->incomings, j)))kh_get_model_io(model_io_map, (uint64_t)(uintptr_t)(*(ccv_cnnp_model_io_t
*)((void*)(((char*)((model_io->incomings)->data)) + (size_t
)(model_io->incomings)->rsize * (size_t)(j)))))
;
592 assert(k != kh_end(model_io_map))((void) sizeof ((k != ((model_io_map)->n_buckets)) ? 1 : 0
), __extension__ ({ if (k != ((model_io_map)->n_buckets)) ;
else __assert_fail ("k != kh_end(model_io_map)", "ccv_cnnp_model_core.c"
, 592, __extension__ __PRETTY_FUNCTION__); }))
;
593 ccv_cnnp_model_io_t input_io = kh_val(model_io_map, k)((model_io_map)->vals[k]);
594 ccv_array_push(model_io_copy->incomings, &input_io);
595 }
596 }
597 if (model_io->dependencies)
598 {
599 model_io_copy->dependencies = ccv_array_new(sizeof(ccv_cnnp_model_io_t), model_io->dependencies->rnum, 0);
600 for (j = 0; j < model_io->dependencies->rnum; j++)
601 {
602 khiter_t k = kh_get(model_io, model_io_map, (uint64_t)(uintptr_t)(*(ccv_cnnp_model_io_t*)ccv_array_get(model_io->dependencies, j)))kh_get_model_io(model_io_map, (uint64_t)(uintptr_t)(*(ccv_cnnp_model_io_t
*)((void*)(((char*)((model_io->dependencies)->data)) + (
size_t)(model_io->dependencies)->rsize * (size_t)(j))))
)
;
603 assert(k != kh_end(model_io_map))((void) sizeof ((k != ((model_io_map)->n_buckets)) ? 1 : 0
), __extension__ ({ if (k != ((model_io_map)->n_buckets)) ;
else __assert_fail ("k != kh_end(model_io_map)", "ccv_cnnp_model_core.c"
, 603, __extension__ __PRETTY_FUNCTION__); }))
;
604 ccv_cnnp_model_io_t input_io = kh_val(model_io_map, k)((model_io_map)->vals[k]);
605 ccv_array_push(model_io_copy->dependencies, &input_io);
606 }
607 }
608 model_io_copy->dependents = model_io->dependents;
609 if (model_io->outgoings)
610 {
611 model_io_copy->outgoings = ccv_array_new(sizeof(ccv_cnnp_model_io_t), model_io->outgoings->rnum, 0);
612 for (j = 0; j < model_io->outgoings->rnum; j++)
613 {
614 khiter_t k = kh_get(model_io, model_io_map, (uint64_t)(uintptr_t)(*(ccv_cnnp_model_io_t*)ccv_array_get(model_io->outgoings, j)))kh_get_model_io(model_io_map, (uint64_t)(uintptr_t)(*(ccv_cnnp_model_io_t
*)((void*)(((char*)((model_io->outgoings)->data)) + (size_t
)(model_io->outgoings)->rsize * (size_t)(j)))))
;
615 assert(k != kh_end(model_io_map))((void) sizeof ((k != ((model_io_map)->n_buckets)) ? 1 : 0
), __extension__ ({ if (k != ((model_io_map)->n_buckets)) ;
else __assert_fail ("k != kh_end(model_io_map)", "ccv_cnnp_model_core.c"
, 615, __extension__ __PRETTY_FUNCTION__); }))
;
616 ccv_cnnp_model_io_t outgoing_io = kh_val(model_io_map, k)((model_io_map)->vals[k]);
617 ccv_array_push(model_io_copy->outgoings, &outgoing_io);
618 }
619 }
620 }
621 kh_destroy(model_io, model_io_map)kh_destroy_model_io(model_io_map);
622 return (ccv_cnnp_model_t*)functional_model;
623}
624
625ccv_cnnp_model_t* ccv_cnnp_model_new(const ccv_cnnp_model_io_t* const inputs, const int input_size, const ccv_cnnp_model_io_t* const outputs, const int output_size, const int is_trainable, const char* const name)
626{
627 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_core.c", 627, __extension__ __PRETTY_FUNCTION__
); }))
;
628 // Do topological sort.
629 ccv_array_t* const reverse_top = ccv_array_new(sizeof(ccv_cnnp_model_io_t), output_size, 0);
630 int i, j, k;
631 // Go through output one by one, reverse traversal them, to detect potential overlap (overlap means, for example,
632 // outputs[1] is an incoming node for outputs[0]. Thus, if we reverse them, we may have outputs[0] build before outputs[1],
633 // hence, having issues.
634 for (i = 0; i < output_size; i++)
635 outputs[i]->visit = 2;
636 for (i = output_size - 1; i >= 0; i--)
637 {
638 if (outputs[i]->visit == 3) // If we need to remove it, no need to visit.
639 continue;
640 assert(outputs[i]->visit == 2)((void) sizeof ((outputs[i]->visit == 2) ? 1 : 0), __extension__
({ if (outputs[i]->visit == 2) ; else __assert_fail ("outputs[i]->visit == 2"
, "ccv_cnnp_model_core.c", 640, __extension__ __PRETTY_FUNCTION__
); }))
;
641 ccv_array_clear(reverse_top);
642 ccv_array_push(reverse_top, &outputs[i]);
643 for (j = 0; j < reverse_top->rnum; j++)
644 {
645 const ccv_cnnp_model_io_t output = *(ccv_cnnp_model_io_t*)ccv_array_get(reverse_top, j)((void*)(((char*)((reverse_top)->data)) + (size_t)(reverse_top
)->rsize * (size_t)(j)))
;
646 assert(!CCV_CNNP_IS_MODEL_INPUT(output->model))((void) sizeof ((!((output->model)->isa == &ccv_cnnp_input_isa
)) ? 1 : 0), __extension__ ({ if (!((output->model)->isa
== &ccv_cnnp_input_isa)) ; else __assert_fail ("!CCV_CNNP_IS_MODEL_INPUT(output->model)"
, "ccv_cnnp_model_core.c", 646, __extension__ __PRETTY_FUNCTION__
); }))
;
647 // If it is input, push it here.
648 if (output->incomings && !CCV_CNNP_IS_MODEL_PARAMETER(output)((output)->param_ref != 0 || (output)->param_sel != 0))
649 for (k = 0; k < output->incomings->rnum; k++)
650 {
651 const ccv_cnnp_model_io_t input = *(ccv_cnnp_model_io_t*)ccv_array_get(output->incomings, k)((void*)(((char*)((output->incomings)->data)) + (size_t
)(output->incomings)->rsize * (size_t)(k)))
;
652 // If it is an input or parameter, skip.
653 if (CCV_CNNP_IS_MODEL_INPUT(input->model)((input->model)->isa == &ccv_cnnp_input_isa) || CCV_CNNP_IS_MODEL_PARAMETER(input)((input)->param_ref != 0 || (input)->param_sel != 0))
654 continue;
655 if (input->visit == 1 || input->visit == 3) // Visited, skip.
656 continue;
657 // If this is an output, we need to remove it from the output array. Otherwise mark it as visited.
658 input->visit = input->visit == 2 ? 3 : 1;
659 ccv_array_push(reverse_top, &input);
660 }
661 // Similar for dependencies.
662 if (output->dependencies && !CCV_CNNP_IS_MODEL_PARAMETER(output)((output)->param_ref != 0 || (output)->param_sel != 0))
663 for (k = 0; k < output->dependencies->rnum; k++)
664 {
665 const ccv_cnnp_model_io_t dependency = *(ccv_cnnp_model_io_t*)ccv_array_get(output->dependencies, k)((void*)(((char*)((output->dependencies)->data)) + (size_t
)(output->dependencies)->rsize * (size_t)(k)))
;
666 // If it is an input or parameter, skip.
667 if (CCV_CNNP_IS_MODEL_INPUT(dependency->model)((dependency->model)->isa == &ccv_cnnp_input_isa) || CCV_CNNP_IS_MODEL_PARAMETER(dependency)((dependency)->param_ref != 0 || (dependency)->param_sel
!= 0)
)
668 continue;
669 if (dependency->visit == 1 || dependency->visit == 3) // Visited, skip.
670 continue;
671 // If this is an output, we need to remove it from the output array. Otherwise mark it as visited.
672 dependency->visit = dependency->visit == 2 ? 3 : 1;
673 ccv_array_push(reverse_top, &dependency);
674 }
675 }
676 for (j = 1; j < reverse_top->rnum; j++)
677 {
678 const ccv_cnnp_model_io_t output = *(ccv_cnnp_model_io_t*)ccv_array_get(reverse_top, j)((void*)(((char*)((reverse_top)->data)) + (size_t)(reverse_top
)->rsize * (size_t)(j)))
;
679 if (output->visit == 1) // Clean the visit back.
680 output->visit = 0;
681 }
682 }
683 ccv_array_clear(reverse_top);
684 for (i = 0; i < output_size; i++) // We will assign sequence in reverse order, thus, reverse the reverse top when copying the outputs.
685 {
686 if (outputs[output_size - 1 - i]->visit == 2)
687 ccv_array_push(reverse_top, &outputs[output_size - 1 - i]);
688 assert(outputs[output_size - 1 - i]->visit == 2 || outputs[output_size - 1 - i]->visit == 3)((void) sizeof ((outputs[output_size - 1 - i]->visit == 2 ||
outputs[output_size - 1 - i]->visit == 3) ? 1 : 0), __extension__
({ if (outputs[output_size - 1 - i]->visit == 2 || outputs
[output_size - 1 - i]->visit == 3) ; else __assert_fail ("outputs[output_size - 1 - i]->visit == 2 || outputs[output_size - 1 - i]->visit == 3"
, "ccv_cnnp_model_core.c", 688, __extension__ __PRETTY_FUNCTION__
); }))
;
689 outputs[output_size - 1 - i]->visit = 0; // Clean up all visits.
690 }
691 // Go from the output, until we meet inputs.
692 uint64_t input_bitmask[((input_size - 1) >> 6) + 1];
693 memset(input_bitmask, 0, sizeof(uint64_t) * (((input_size - 1) >> 6) + 1));
694 int tensor_output_size = 0; // io can be mapped to multiple tensor outputs, therefore, need to compute the exact tensor output size.
695 for (i = 0; i < output_size; i++)
696 tensor_output_size += outputs[i]->model->output_size;
697 for (i = 0; i < reverse_top->rnum; i++)
698 {
699 const ccv_cnnp_model_io_t output = *(ccv_cnnp_model_io_t*)ccv_array_get(reverse_top, i)((void*)(((char*)((reverse_top)->data)) + (size_t)(reverse_top
)->rsize * (size_t)(i)))
;
700 assert(!CCV_CNNP_IS_MODEL_INPUT(output->model))((void) sizeof ((!((output->model)->isa == &ccv_cnnp_input_isa
)) ? 1 : 0), __extension__ ({ if (!((output->model)->isa
== &ccv_cnnp_input_isa)) ; else __assert_fail ("!CCV_CNNP_IS_MODEL_INPUT(output->model)"
, "ccv_cnnp_model_core.c", 700, __extension__ __PRETTY_FUNCTION__
); }))
;
701 // If it is input, push it here.
702 if (output->incomings && !CCV_CNNP_IS_MODEL_PARAMETER(output)((output)->param_ref != 0 || (output)->param_sel != 0))
703 for (j = 0; j < output->incomings->rnum; j++)
704 {
705 const ccv_cnnp_model_io_t input = *(ccv_cnnp_model_io_t*)ccv_array_get(output->incomings, j)((void*)(((char*)((output->incomings)->data)) + (size_t
)(output->incomings)->rsize * (size_t)(j)))
;
706 ++input->visit; // Mark it as visited.
707 if (input->visit != input->outgoings->rnum + input->dependents) // Not all dependencies visited.
708 continue;
709 if (!CCV_CNNP_IS_MODEL_INPUT(input->model)((input->model)->isa == &ccv_cnnp_input_isa) && !CCV_CNNP_IS_MODEL_PARAMETER(input)((input)->param_ref != 0 || (input)->param_sel != 0))
710 ccv_array_push(reverse_top, &input);
711 else if (CCV_CNNP_IS_MODEL_INPUT(input->model)((input->model)->isa == &ccv_cnnp_input_isa)) {
712 for (k = 0; k < input_size; k++)
713 if (input == inputs[k])
714 break;
715 assert(k < input_size)((void) sizeof ((k < input_size) ? 1 : 0), __extension__ (
{ if (k < input_size) ; else __assert_fail ("k < input_size"
, "ccv_cnnp_model_core.c", 715, __extension__ __PRETTY_FUNCTION__
); }))
;
716 input_bitmask[k >> 6] |= ((uint64_t)1 << (k & 63));
717 }
718 }
719 if (output->dependencies && !CCV_CNNP_IS_MODEL_PARAMETER(output)((output)->param_ref != 0 || (output)->param_sel != 0))
720 for (j = 0; j < output->dependencies->rnum; j++)
721 {
722 const ccv_cnnp_model_io_t dependency = *(ccv_cnnp_model_io_t*)ccv_array_get(output->dependencies, j)((void*)(((char*)((output->dependencies)->data)) + (size_t
)(output->dependencies)->rsize * (size_t)(j)))
;
723 ++dependency->visit; // Mark it as visited.
724 if (dependency->visit != (dependency->outgoings ? dependency->outgoings->rnum : 0) + dependency->dependents) // Not all dependencies visited.
725 continue;
726 if (!CCV_CNNP_IS_MODEL_INPUT(dependency->model)((dependency->model)->isa == &ccv_cnnp_input_isa) && !CCV_CNNP_IS_MODEL_PARAMETER(dependency)((dependency)->param_ref != 0 || (dependency)->param_sel
!= 0)
)
727 ccv_array_push(reverse_top, &dependency);
728 else if (CCV_CNNP_IS_MODEL_INPUT(dependency->model)((dependency->model)->isa == &ccv_cnnp_input_isa)) {
729 for (k = 0; k < input_size; k++)
730 if (dependency == inputs[k])
731 break;
732 assert(k < input_size)((void) sizeof ((k < input_size) ? 1 : 0), __extension__ (
{ if (k < input_size) ; else __assert_fail ("k < input_size"
, "ccv_cnnp_model_core.c", 732, __extension__ __PRETTY_FUNCTION__
); }))
;
733 input_bitmask[k >> 6] |= ((uint64_t)1 << (k & 63));
734 }
735 }
736 }
737 for (i = 0; i < reverse_top->rnum; i++)
738 {
739 const ccv_cnnp_model_io_t output = *(ccv_cnnp_model_io_t*)ccv_array_get(reverse_top, i)((void*)(((char*)((reverse_top)->data)) + (size_t)(reverse_top
)->rsize * (size_t)(i)))
;
740 output->visit = 0; // Clean the visit back.
741 }
742 for (i = 0; i < input_size; i++)
743 inputs[i]->visit = 0; // Clean the visit back.
744 for (i = 0; i < input_size; i++)
745 { assert((input_bitmask[i >> 6] & ((uint64_t)1 << (i & 63))))((void) sizeof (((input_bitmask[i >> 6] & ((uint64_t
)1 << (i & 63)))) ? 1 : 0), __extension__ ({ if ((input_bitmask
[i >> 6] & ((uint64_t)1 << (i & 63)))) ; else
__assert_fail ("(input_bitmask[i >> 6] & ((uint64_t)1 << (i & 63)))"
, "ccv_cnnp_model_core.c", 745, __extension__ __PRETTY_FUNCTION__
); }))
; } // Assuming they all match.
746 const int sequence_size = reverse_top->rnum + input_size;
747 ccv_cnnp_functional_model_t* const functional_model = (ccv_cnnp_functional_model_t*)cccalloccalloc(1, sizeof(ccv_cnnp_functional_model_t) + sizeof(ccv_cnnp_model_t*) * (sequence_size - 1) + sizeof(ccv_nnc_tensor_symbol_t) * tensor_output_size + sizeof(int) * output_size);
748 functional_model->super.isa = &ccv_cnnp_functional_model_isa;
749 functional_model->super.outputs = (ccv_nnc_tensor_symbol_t*)(functional_model->sequence + sequence_size);
750 functional_model->super.output_size = tensor_output_size;
751 functional_model->super.input_size = input_size;
752 functional_model->super.is_trainable = is_trainable;
753 functional_model->model_output_size = output_size;
754 functional_model->model_outputs = (int*)(functional_model->super.outputs + tensor_output_size);
755 ccv_cnnp_model_copy_name(&functional_model->super, name);
756 functional_model->sequence_size = sequence_size;
757 memcpy(functional_model->sequence, inputs, sizeof(ccv_cnnp_model_io_t) * input_size);
758 for (i = 0; i < reverse_top->rnum; i++)
759 functional_model->sequence[input_size + i] = *(ccv_cnnp_model_io_t*)ccv_array_get(reverse_top, reverse_top->rnum - 1 - i)((void*)(((char*)((reverse_top)->data)) + (size_t)(reverse_top
)->rsize * (size_t)(reverse_top->rnum - 1 - i)))
;
760 for (i = 0; i < output_size; i++)
761 {
762 for (j = sequence_size - 1; j >= input_size; j--)
763 if (functional_model->sequence[j] == outputs[i])
764 {
765 functional_model->model_outputs[i] = j;
766 break;
767 }
768 }
769 ccv_array_free(reverse_top);
770 return (ccv_cnnp_model_t*)functional_model;
771}
772
773static ccv_cnnp_model_t* _ccv_cnnp_input_copy(const ccv_cnnp_model_t* const self, void* const context)
774{
775 ccv_cnnp_model_t* const input = (ccv_cnnp_model_t*)cccalloccalloc(1, sizeof(ccv_cnnp_model_t) + sizeof(ccv_nnc_tensor_symbol_t));
776 input->isa = &ccv_cnnp_input_isa;
777 input->outputs = (ccv_nnc_tensor_symbol_t*)(input + 1);
778 input->output_size = 1;
779 return input;
780}
781
782static const ccv_cnnp_model_vtab_t ccv_cnnp_input_isa = {
783 .copy = _ccv_cnnp_input_copy,
784};
785
786ccv_cnnp_model_io_t ccv_cnnp_input(void)
787{
788 ccv_cnnp_model_t* const input = (ccv_cnnp_model_t*)cccalloccalloc(1, sizeof(ccv_cnnp_model_t) + sizeof(ccv_nnc_tensor_symbol_t));
789 input->isa = &ccv_cnnp_input_isa;
790 input->io = ccv_array_new(sizeof(ccv_cnnp_model_io_t), 1, 0);
791 ccv_cnnp_model_io_t input_io = ccmallocmalloc(sizeof(struct ccv_cnnp_model_io_s) + sizeof(ccv_nnc_tensor_symbol_t));
792 input_io->param_ref = 0;
793 input_io->param_sel = 0;
794 input_io->visit = 0;
795 input_io->incomings = 0;
796 input_io->dependencies = 0;
797 input_io->dependents = 0;
798 input_io->outgoings = 0;
799 input_io->model = input;
800 input_io->outputs = (ccv_nnc_tensor_symbol_t*)(input_io + 1);
801 ccv_array_push(input->io, &input_io);
802 input->outputs = (ccv_nnc_tensor_symbol_t*)(input + 1);
803 input->output_size = 1;
804 return input_io;
805}
806
807// MARK - Dynamic Layer
808
809typedef struct {
810 ccv_cnnp_model_t super;
811 ccv_cnnp_model_dynamic_f func;
812 void* context;
813 ccv_cnnp_model_t* model;
814} ccv_cnnp_dynamic_model_t;
815
816static void _ccv_cnnp_dynamic_model_deinit(ccv_cnnp_model_t* const super)
817{
818 ccv_cnnp_dynamic_model_t* const self = (ccv_cnnp_dynamic_model_t*)super;
819 if (self->model)
820 ccv_cnnp_model_deinit(self->model);
821}
822
823static void _ccv_cnnp_dynamic_model_dealloc(ccv_cnnp_model_t* const super)
824{
825 ccv_cnnp_dynamic_model_t* const self = (ccv_cnnp_dynamic_model_t*)super;
826 if (self->model)
827 ccv_cnnp_model_free(self->model);
828}
829
830static void _ccv_cnnp_dynamic_model_build(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_nnc_tensor_symbol_t* const inputs, const int input_size, ccv_nnc_tensor_symbol_t* const outputs, const int output_size)
831{
832 ccv_cnnp_dynamic_model_t* const self = (ccv_cnnp_dynamic_model_t*)super;
833 PRINT(CCV_CLI_VERBOSE, "[cnnp_dynamic_model_build] 1. %p, func: %p\n", self, self->func)do { if ((CCV_CLI_VERBOSE & ccv_cli_get_output_levels()))
{ printf("[cnnp_dynamic_model_build] 1. %p, func: %p\n", self
, self->func); fflush(stdout); } } while (0)
;
834 if (!self->model)
835 {
836 ccv_nnc_tensor_param_t input_params[input_size];
837 int i;
838 for (i = 0; i < input_size; i++)
839 input_params[i] = ccv_nnc_tensor_symbol_params(graph, inputs[i]);
840 self->model = self->func(input_params, input_size, self->context);
841 // Update to use the settings of the compiled model.
842 self->super.input_size = self->model->input_size;
843 self->super.outputs = self->model->outputs;
844 self->super.output_size = self->model->output_size;
845 }
846 self->model->data = self->super.data;
847 ccv_cnnp_model_build(self->model, graph, inputs, input_size, outputs, output_size);
848 self->model->data = 0;
849 PRINT(CCV_CLI_VERBOSE, "[cnnp_dynamic_model_build] 2. %p\n", self)do { if ((CCV_CLI_VERBOSE & ccv_cli_get_output_levels()))
{ printf("[cnnp_dynamic_model_build] 2. %p\n", self); fflush
(stdout); } } while (0)
;
850}
851
852static void _ccv_cnnp_dynamic_model_init_states(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_cnnp_state_initializer_f initializer, void* const context)
853{
854 ccv_cnnp_dynamic_model_t* const self = (ccv_cnnp_dynamic_model_t*)super;
855 assert(self->model)((void) sizeof ((self->model) ? 1 : 0), __extension__ ({ if
(self->model) ; else __assert_fail ("self->model", "ccv_cnnp_model_core.c"
, 855, __extension__ __PRETTY_FUNCTION__); }))
;
856 ccv_cnnp_model_init_states(self->model, graph, initializer, context);
857}
858
859static void _ccv_cnnp_dynamic_model_set_is_test(ccv_cnnp_model_t* const super, const int is_test, const ccv_cnnp_cmd_updater_f updater, void* const context)
860{
861 ccv_cnnp_dynamic_model_t* const self = (ccv_cnnp_dynamic_model_t*)super;
862 assert(self->model)((void) sizeof ((self->model) ? 1 : 0), __extension__ ({ if
(self->model) ; else __assert_fail ("self->model", "ccv_cnnp_model_core.c"
, 862, __extension__ __PRETTY_FUNCTION__); }))
;
863 ccv_cnnp_model_set_is_test(self->model, is_test, updater, context);
864}
865
866static ccv_cnnp_model_t* _ccv_cnnp_dynamic_model_copy(const ccv_cnnp_model_t* const super, void* const context);
867
868static void _ccv_cnnp_dynamic_model_add_to_parameter_indices(ccv_cnnp_model_t* const super, const int index, ccv_array_t* const parameter_indices)
869{
870 ccv_cnnp_dynamic_model_t* const self = (ccv_cnnp_dynamic_model_t*)super;
871 assert(self->model)((void) sizeof ((self->model) ? 1 : 0), __extension__ ({ if
(self->model) ; else __assert_fail ("self->model", "ccv_cnnp_model_core.c"
, 871, __extension__ __PRETTY_FUNCTION__); }))
;
872 ccv_cnnp_model_add_to_parameter_indices(self->model, index, parameter_indices);
873}
874
875static void _ccv_cnnp_dynamic_model_notify(const ccv_cnnp_model_t* const super, const int tag, void* const payload)
876{
877 ccv_cnnp_dynamic_model_t* const self = (ccv_cnnp_dynamic_model_t*)super;
878 if (self->model)
879 ccv_cnnp_model_notify(self->model, tag, payload);
880}
881
882static const ccv_cnnp_model_vtab_t ccv_cnnp_dynamic_model_isa = {
883 .deinit = _ccv_cnnp_dynamic_model_deinit,
884 .dealloc = _ccv_cnnp_dynamic_model_dealloc,
885 .build = _ccv_cnnp_dynamic_model_build,
886 .init_states = _ccv_cnnp_dynamic_model_init_states,
887 .copy = _ccv_cnnp_dynamic_model_copy,
888 .set_is_test = _ccv_cnnp_dynamic_model_set_is_test,
889 .add_to_parameter_indices = _ccv_cnnp_dynamic_model_add_to_parameter_indices,
890 .notify = _ccv_cnnp_dynamic_model_notify,
891};
892
893ccv_cnnp_model_t* ccv_cnnp_dynamic_new(ccv_cnnp_model_dynamic_f func, void* const context, const char* const name)
894{
895 ccv_cnnp_dynamic_model_t* const dynamic_model = (ccv_cnnp_dynamic_model_t*)cccalloccalloc(1, sizeof(ccv_cnnp_dynamic_model_t));
896 dynamic_model->super.isa = &ccv_cnnp_dynamic_model_isa;
897 dynamic_model->super.is_trainable = -1;
898 dynamic_model->func = func;
899 dynamic_model->context = context;
900 ccv_cnnp_model_copy_name(&dynamic_model->super, name);
901 return (ccv_cnnp_model_t*)dynamic_model;
902}
903
904static ccv_cnnp_model_t* _ccv_cnnp_dynamic_model_copy(const ccv_cnnp_model_t* const super, void* const context)
905{
906 const ccv_cnnp_dynamic_model_t* const self = (const ccv_cnnp_dynamic_model_t*)super;
907 return ccv_cnnp_dynamic_new(self->func, self->context, self->super.name);
908}
909
910// MARK - Command Layer
911
912typedef struct {
913 ccv_cnnp_model_t super;
914 ccv_nnc_cmd_t cmd;
915 ccv_nnc_hint_t hint;
916 ccv_nnc_tensor_symbol_t* input_symbols; // This is only valid for INIT_SHARED_TENSOR / INIT_SHARED_TENSOR_AS_TRAINABLE
917 ccv_nnc_tensor_symbol_t* output_symbols; // This is just for the output symbol (in case we need to have no tensor symbol).
918 ccv_cnnp_cmd_exec_io_t* inputs;
919 int flags;
920 int input_size;
921 int* outputs;
922 int output_size;
923} ccv_cnnp_model_cmd_exec_t;
924
925static void _ccv_cnnp_cmd_exec_build(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_nnc_tensor_symbol_t* const inputs, const int input_size, ccv_nnc_tensor_symbol_t* const outputs, const int output_size)
926{
927 ccv_cnnp_model_cmd_exec_t* const self = (ccv_cnnp_model_cmd_exec_t*)super;
928 PRINT(CCV_CLI_VERBOSE, "[cnnp_cmd_exec_build] -\n")do { if ((CCV_CLI_VERBOSE & ccv_cli_get_output_levels()))
{ printf("[cnnp_cmd_exec_build] -\n"); fflush(stdout); } } while
(0)
;
929 ccv_nnc_tensor_param_t input_params[ccv_max(1, self->input_size)({ typeof (1) _a = (1); typeof (self->input_size) _b = (self
->input_size); (_a > _b) ? _a : _b; })
];
930 int i, j;
931 for (i = 0, j = 0; i < self->input_size; i++)
932 if (self->inputs[i].type == CCV_CNNP_IO)
933 {
934 self->input_symbols[i] = inputs[j++];
935 input_params[i] = ccv_nnc_tensor_symbol_params(graph, self->input_symbols[i]);
936 } else if (self->inputs[i].type == CCV_CNNP_NO_TENSOR) {
937 self->input_symbols[i] = NO_TENSOR_SYMBOL(const ccv_nnc_tensor_symbol_t){.d = CCV_NNC_NO_TENSOR_SYMBOL
}
;
938 } else if (!self->input_symbols[i].graph) {
939 // Otherwise, we only create this symbol if it doesn't exist.
940 const ccv_nnc_tensor_param_t params = self->inputs[i].init_state.info;
941 input_params[i] = params;
942 self->input_symbols[i] = ccv_nnc_tensor_symbol_new(graph, params, 0);
943 }
944 // We cannot simply mark the outputs as auto, because the subsequent build call may require this output to have params setup.
945 // Infer the parameters here.
946 ccv_nnc_tensor_param_t output_params[ccv_max(1, self->output_size)({ typeof (1) _a = (1); typeof (self->output_size) _b = (self
->output_size); (_a > _b) ? _a : _b; })
];
947 ccv_nnc_hint_tensor_auto(self->cmd, input_params, self->input_size, self->hint, output_params, self->output_size);
948 for (i = 0, j = 0; i < self->output_size; i++)
949 if (self->outputs[i] == CCV_CNNP_IO)
950 self->output_symbols[i] = outputs[j++] = ccv_nnc_tensor_symbol_new(graph, output_params[i], 0);
951 else if (self->outputs[i] == CCV_CNNP_TENSOR_NOT_OUTPUT)
952 self->output_symbols[i] = ccv_nnc_tensor_symbol_new(graph, output_params[i], 0);
953 else
954 self->output_symbols[i] = NO_TENSOR_SYMBOL(const ccv_nnc_tensor_symbol_t){.d = CCV_NNC_NO_TENSOR_SYMBOL
}
;
955 ccv_nnc_graph_exec_symbol_new(graph, self->cmd, self->input_symbols, self->input_size, self->output_symbols, self->output_size, 0);
956}
957
958static void _ccv_cnnp_cmd_exec_init_states(ccv_cnnp_model_t* const super, ccv_nnc_symbolic_graph_t* const graph, const ccv_cnnp_state_initializer_f initializer, void* const context)
959{
960 ccv_cnnp_model_cmd_exec_t* const self = (ccv_cnnp_model_cmd_exec_t*)super;
961 int i;
962 for (i = 0; i < self->input_size; i++)
963 if (self->inputs[i].type == CCV_CNNP_INIT_SHARED_TENSOR || self->inputs[i].type == CCV_CNNP_INIT_SHARED_TENSOR_AS_TRAINABLE)
964 self->inputs[i].init_state.init(self->input_symbols[i], initializer, context, self->inputs[i].init_state.context);
965}
966
967static void _ccv_cnnp_cmd_exec_add_to_output(ccv_cnnp_model_t* const super, const ccv_cnnp_add_to_array_f add_to_array, void* const outputs)
968{
969 ccv_cnnp_model_cmd_exec_t* const self = (ccv_cnnp_model_cmd_exec_t*)super;
970 int i;
971 for (i = 0; i < self->input_size; i++)
972 if (self->inputs[i].type == CCV_CNNP_INIT_SHARED_TENSOR)
973 add_to_array(outputs, self->input_symbols[i], 0); // Push this as retainable because it need to be init.
974}
975
976static void _ccv_cnnp_cmd_exec_add_to_parameter(ccv_cnnp_model_t* const super, const ccv_cnnp_add_to_array_f add_to_array, void* const parameters, const int is_trainable)
977{
978 ccv_cnnp_model_cmd_exec_t* const self = (ccv_cnnp_model_cmd_exec_t*)super;
979 int i;
980 for (i = 0; i < self->input_size; i++)
981 if (self->inputs[i].type == CCV_CNNP_INIT_SHARED_TENSOR_AS_TRAINABLE)
982 add_to_array(parameters, self->input_symbols[i], is_trainable); // Push this as parameter.
983}
984
985static void _ccv_cnnp_cmd_exec_deinit(ccv_cnnp_model_t* const super)
986{
987 ccv_cnnp_model_cmd_exec_t* const self = (ccv_cnnp_model_cmd_exec_t*)super;
988 int i, j;
989 for (i = 0; i < self->input_size; i++)
990 if ((self->inputs[i].type == CCV_CNNP_INIT_SHARED_TENSOR || self->inputs[i].type == CCV_CNNP_INIT_SHARED_TENSOR_AS_TRAINABLE) &&
991 self->inputs[i].init_state.context)
992 {
993 void* const context = self->inputs[i].init_state.context;
994 if (self->inputs[i].init_state.deinit)
995 self->inputs[i].init_state.deinit(context);
996 self->inputs[i].init_state.init = 0;
997 self->inputs[i].init_state.deinit = 0;
998 self->inputs[i].init_state.context = 0;
999 for (j = i + 1; j < self->input_size; j++)
1000 if (self->inputs[j].init_state.context == context)
1001 {
1002 self->inputs[j].init_state.init = 0;
1003 self->inputs[j].init_state.deinit = 0;
1004 self->inputs[j].init_state.context = 0;
1005 }
1006 }
1007}
1008
1009static ccv_cnnp_model_t* _ccv_cnnp_cmd_exec_copy(const ccv_cnnp_model_t* const super, void* const context);
1010
1011static const ccv_cnnp_model_vtab_t ccv_cnnp_cmd_exec_isa = {
1012 .build = _ccv_cnnp_cmd_exec_build,
1013 .init_states = _ccv_cnnp_cmd_exec_init_states,
1014 .add_to_parameter = _ccv_cnnp_cmd_exec_add_to_parameter,
1015 .add_to_output = _ccv_cnnp_cmd_exec_add_to_output,
1016 .deinit = _ccv_cnnp_cmd_exec_deinit,
1017 .copy = _ccv_cnnp_cmd_exec_copy,
1018};
1019
1020static ccv_cnnp_model_t* _ccv_cnnp_cmd_exec(const ccv_nnc_cmd_t cmd, int copy_io, const ccv_nnc_hint_t hint, const int flags, const ccv_cnnp_cmd_exec_io_t* const inputs, const int input_size, const int* const outputs, const int output_size, const int is_trainable, const char* const name)
1021{
1022 assert(input_size >= 0)((void) sizeof ((input_size >= 0) ? 1 : 0), __extension__ (
{ if (input_size >= 0) ; else __assert_fail ("input_size >= 0"
, "ccv_cnnp_model_core.c", 1022, __extension__ __PRETTY_FUNCTION__
); }))
;
1023 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_core.c", 1023, __extension__ __PRETTY_FUNCTION__
); }))
;
1024 int i;
1025 int io_input_size = 0;
1026 for (i = 0; i < input_size; i++)
1027 if (inputs[i].type == CCV_CNNP_IO)
1028 ++io_input_size;
1029 else {
1030 assert(inputs[i].type == CCV_CNNP_INIT_SHARED_TENSOR || inputs[i].type == CCV_CNNP_INIT_SHARED_TENSOR_AS_TRAINABLE)((void) sizeof ((inputs[i].type == CCV_CNNP_INIT_SHARED_TENSOR
|| inputs[i].type == CCV_CNNP_INIT_SHARED_TENSOR_AS_TRAINABLE
) ? 1 : 0), __extension__ ({ if (inputs[i].type == CCV_CNNP_INIT_SHARED_TENSOR
|| inputs[i].type == CCV_CNNP_INIT_SHARED_TENSOR_AS_TRAINABLE
) ; else __assert_fail ("inputs[i].type == CCV_CNNP_INIT_SHARED_TENSOR || inputs[i].type == CCV_CNNP_INIT_SHARED_TENSOR_AS_TRAINABLE"
, "ccv_cnnp_model_core.c", 1030, __extension__ __PRETTY_FUNCTION__
); }))
;
1031 assert(inputs[i].init_state.init)((void) sizeof ((inputs[i].init_state.init) ? 1 : 0), __extension__
({ if (inputs[i].init_state.init) ; else __assert_fail ("inputs[i].init_state.init"
, "ccv_cnnp_model_core.c", 1031, __extension__ __PRETTY_FUNCTION__
); }))
;
1032 }
1033 int io_output_size = 0;
1034 for (i = 0; i < output_size; i++)
1035 if (outputs[i] == CCV_CNNP_IO)
1036 ++io_output_size;
1037 else {
1038 assert(outputs[i] == CCV_CNNP_TENSOR_NOT_OUTPUT || outputs[i] == CCV_CNNP_NO_TENSOR)((void) sizeof ((outputs[i] == CCV_CNNP_TENSOR_NOT_OUTPUT || outputs
[i] == CCV_CNNP_NO_TENSOR) ? 1 : 0), __extension__ ({ if (outputs
[i] == CCV_CNNP_TENSOR_NOT_OUTPUT || outputs[i] == CCV_CNNP_NO_TENSOR
) ; else __assert_fail ("outputs[i] == CCV_CNNP_TENSOR_NOT_OUTPUT || outputs[i] == CCV_CNNP_NO_TENSOR"
, "ccv_cnnp_model_core.c", 1038, __extension__ __PRETTY_FUNCTION__
); }))
;
1039 }
1040 assert(io_output_size > 0)((void) sizeof ((io_output_size > 0) ? 1 : 0), __extension__
({ if (io_output_size > 0) ; else __assert_fail ("io_output_size > 0"
, "ccv_cnnp_model_core.c", 1040, __extension__ __PRETTY_FUNCTION__
); }))
;
1041 ccv_cnnp_model_cmd_exec_t* const model_cmd_exec = (ccv_cnnp_model_cmd_exec_t*)cccalloccalloc(1, sizeof(ccv_cnnp_model_cmd_exec_t) + sizeof(ccv_nnc_tensor_symbol_t) * (io_output_size + input_size + output_size) + sizeof(ccv_cnnp_cmd_exec_io_t) * input_size + sizeof(int) * output_size);
1042 model_cmd_exec->super.isa = &ccv_cnnp_cmd_exec_isa;
1043 model_cmd_exec->super.input_size = io_input_size;
1044 model_cmd_exec->super.outputs = (ccv_nnc_tensor_symbol_t*)(model_cmd_exec + 1);
1045 model_cmd_exec->super.output_size = io_output_size;
1046 model_cmd_exec->super.is_trainable = is_trainable;
1047 ccv_cnnp_model_copy_name(&model_cmd_exec->super, name);
1048 model_cmd_exec->cmd = cmd;
1049 model_cmd_exec->hint = hint;
1050 model_cmd_exec->flags = flags;
1051 model_cmd_exec->input_size = input_size;
1052 model_cmd_exec->input_symbols = model_cmd_exec->super.outputs + io_output_size;
1053 model_cmd_exec->output_symbols = model_cmd_exec->input_symbols + input_size;
1054 model_cmd_exec->inputs = (ccv_cnnp_cmd_exec_io_t*)(model_cmd_exec->output_symbols + output_size);
1055 if (input_size > 0)
1056 {
1057 memcpy(model_cmd_exec->inputs, inputs, sizeof(ccv_cnnp_cmd_exec_io_t) * input_size);
1058 if (copy_io)
1059 for (i = 0; i < input_size; i++)
1060 if (inputs[i].type != CCV_CNNP_IO && inputs[i].init_state.copy)
1061 model_cmd_exec->inputs[i].init_state.context = inputs[i].init_state.copy(inputs[i].init_state.context);
1062 }
1063 model_cmd_exec->output_size = output_size;
1064 model_cmd_exec->outputs = (int*)(model_cmd_exec->inputs + input_size);
1065 if (output_size > 0)
1066 memcpy(model_cmd_exec->outputs, outputs, sizeof(int) * output_size);
1067 return (ccv_cnnp_model_t*)model_cmd_exec;
1068}
1069
1070ccv_cnnp_model_t* ccv_cnnp_cmd_exec(const ccv_nnc_cmd_t cmd, const ccv_nnc_hint_t hint, const int flags, const ccv_cnnp_cmd_exec_io_t* const inputs, const int input_size, const int* const outputs, const int output_size, const int is_trainable, const char* const name)
1071{
1072 return _ccv_cnnp_cmd_exec(cmd, 0, hint, flags, inputs, input_size, outputs, output_size, is_trainable, name);
1073}
1074
1075static ccv_cnnp_model_t* _ccv_cnnp_cmd_exec_copy(const ccv_cnnp_model_t* const super, void* const context)
1076{
1077 const ccv_cnnp_model_cmd_exec_t* const self = (const ccv_cnnp_model_cmd_exec_t*)super;
1078 return _ccv_cnnp_cmd_exec(self->cmd, 1, self->hint, self->flags, self->inputs, self->input_size, self->outputs, self->output_size, self->super.is_trainable, self->super.name);
1079}
1080
1081static void _ccv_cnnp_cmd_exec_io_copy(const ccv_nnc_tensor_symbol_t tensor_symbol, const ccv_cnnp_state_initializer_f initializer, void* const initializer_context, void* const context)
1082{
1083 initializer(initializer_context, CMD_DATA_TRANSFER_FORWARD()ccv_nnc_cmd(CCV_NNC_DATA_TRANSFER_FORWARD, 0, ccv_nnc_cmd_auto
, 0)
, ccv_nnc_no_hint, 0, (ccv_nnc_tensor_t*)context, tensor_symbol);
1084}
1085
1086ccv_cnnp_cmd_exec_io_init_state_t ccv_cnnp_cmd_exec_io_copy(const ccv_nnc_tensor_t* const tensor)
1087{
1088 return (ccv_cnnp_cmd_exec_io_init_state_t){
1089 .info = tensor->info,
1090 .context = (void *)tensor,
1091 .init = _ccv_cnnp_cmd_exec_io_copy,
1092 };
1093}
1094
1095typedef struct {
1096 ccv_nnc_cmd_t cmd;
1097 ccv_nnc_hint_t hint;
1098 int flags;
1099} ccv_cnnp_cmd_exec_io_set_by_t;
1100
1101static void _ccv_cnnp_cmd_exec_io_set_by(const ccv_nnc_tensor_symbol_t tensor_symbol, const ccv_cnnp_state_initializer_f initializer, void* const initializer_context, void* const context)
1102{
1103 const ccv_cnnp_cmd_exec_io_set_by_t* const set_by = (ccv_cnnp_cmd_exec_io_set_by_t*)context;
1104 initializer(initializer_context, set_by->cmd, set_by->hint, set_by->flags, 0, tensor_symbol);
1105}
1106
1107static void* _ccv_cnnp_cmd_exec_io_set_by_copy(void* const context)
1108{
1109 ccv_cnnp_cmd_exec_io_set_by_t* const set_by = (ccv_cnnp_cmd_exec_io_set_by_t*)ccmallocmalloc(sizeof(ccv_cnnp_cmd_exec_io_set_by_t));
1110 memcpy(set_by, context, sizeof(ccv_cnnp_cmd_exec_io_set_by_t));
1111 return set_by;
1112}
1113
1114ccv_cnnp_cmd_exec_io_init_state_t ccv_cnnp_cmd_exec_io_set_by(const ccv_nnc_cmd_t cmd, const ccv_nnc_hint_t hint, const int flags, const ccv_nnc_tensor_param_t params)
1115{
1116 ccv_cnnp_cmd_exec_io_set_by_t* const set_by = (ccv_cnnp_cmd_exec_io_set_by_t*)ccmallocmalloc(sizeof(ccv_cnnp_cmd_exec_io_set_by_t));
1117 set_by->cmd = cmd;
1118 set_by->hint = hint;
1119 set_by->flags = flags;
1120 return (ccv_cnnp_cmd_exec_io_init_state_t){
1121 .info = params,
1122 .context = set_by,
1123 .init = _ccv_cnnp_cmd_exec_io_set_by,
1124 .copy = _ccv_cnnp_cmd_exec_io_set_by_copy,
1125 .deinit = ccfreefree,
1126 };
1127}