Bug Summary

File:nnc/ccv_cnnp_model_core.c
Warning:line 389, column 36
Array access (via field 'vals') results in a null pointer dereference

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-29-185027-1360645-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 int is_trainable, 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 = is_trainable;
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.is_trainable, 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; } }
11
Null pointer value stored to field 'vals'
20
Taking true branch
21
Taking false branch
22
Calling 'kh_resize_io_node'
23
Taking true branch
24
Assuming the condition is false
25
Taking false branch
26
'?' condition is true
27
Assuming 'new_flags' is null
28
Taking true branch
29
Returning without writing to 'h->vals'
30
Returning from 'kh_resize_io_node'
31
Taking true branch
32
Returning without writing to 'h->vals'
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)
;
1
Assuming the condition is false
2
Taking false branch
3
Loop condition is false. Exiting loop
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__
); }))
;
4
Assuming 'input_size' is equal to field 'input_size'
5
Taking true branch
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__
); }))
;
6
Assuming 'output_size' is equal to field 'output_size'
7
Taking true branch
337 int i, j, k;
338 for (i = 0; i < self->super.input_size; i++)
8
Assuming 'i' is >= field 'input_size'
9
Loop condition is false. Execution continues on line 340
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();
10
Calling 'kh_init_io_node'
12
Returning from 'kh_init_io_node'
343 for (i = self->super.input_size; i < self->sequence_size; i++)
13
Assuming 'i' is < field 'sequence_size'
14
Loop condition is true. Entering loop body
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)
15
Assuming 'incomings' is null
16
Taking false branch
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)
17
Assuming 'dependencies' is non-null
18
Assuming field 'rnum' is > 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)
;
19
Calling 'kh_put_io_node'
33
Returning from 'kh_put_io_node'
388 if (ret
33.1
'ret' is not equal to 0
!= 0)
34
Taking true branch
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);
35
Array access (via field 'vals') results in a null pointer dereference
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; } }
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();
505 int i, j;
506 for (i = 0; i < self->sequence_size; i++)
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++)
533 {
534 if (self->sequence[i]->incomings)
535 for (j = 0; j < self->sequence[i]->incomings->rnum; j++)
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.
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)
;
542 if (ret != 0)
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}