File: | nnc/ccv_cnnp_model_core.c |
Warning: | line 292, column 1 Assigned value is garbage or undefined |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | |
10 | static 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 | |
16 | typedef 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 | |
22 | static 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; |
26 | for (i = 0; i < self->sequence_size; i++) |
27 | { |
28 | ccv_cnnp_model_t* const model = self->sequence[i]; |
29 | if (!model) |
30 | continue; |
31 | ccv_cnnp_model_free(model); |
32 | for (j = i + 1; j < self->sequence_size; j++) |
33 | if (self->sequence[j] == model) |
34 | self->sequence[j] = 0; |
35 | } |
36 | } |
37 | |
38 | static 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) |
39 | { |
40 | ccv_cnnp_sequential_model_t* const self = (ccv_cnnp_sequential_model_t*)super; |
41 | ccv_cnnp_model_t* const sub_model = self->sequence[0]; |
42 | // Go through each sub model to build the graph. |
43 | ccv_nnc_tensor_symbol_t input; |
44 | sub_model->data = self->super.data; |
45 | ccv_cnnp_model_build(sub_model, graph, inputs, input_size, &input, 1); |
46 | sub_model->data = 0; |
47 | int i; |
48 | for (i = 1; i < self->sequence_size; i++) |
49 | { |
50 | ccv_nnc_tensor_symbol_t output; |
51 | ccv_cnnp_model_t* const sub_model = self->sequence[i]; |
52 | // Go through each sub model to build the graph. |
53 | sub_model->data = self->super.data; |
54 | ccv_cnnp_model_build(sub_model, graph, &input, 1, &output, 1); |
55 | sub_model->data = 0; |
56 | input = output; |
57 | } |
58 | outputs[0] = input; |
59 | } |
60 | |
61 | static 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) |
62 | { |
63 | ccv_cnnp_sequential_model_t* const self = (ccv_cnnp_sequential_model_t*)super; |
64 | int i; |
65 | for (i = 0; i < self->sequence_size; i++) |
66 | ccv_cnnp_model_init_states(self->sequence[i], graph, initializer, context); |
67 | } |
68 | |
69 | static 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) |
70 | { |
71 | ccv_cnnp_sequential_model_t* const self = (ccv_cnnp_sequential_model_t*)super; |
72 | int i; |
73 | for (i = 0; i < self->sequence_size; i++) |
74 | ccv_cnnp_model_set_is_test(self->sequence[i], is_test, updater, context); |
75 | } |
76 | |
77 | static ccv_cnnp_model_t* _ccv_cnnp_sequential_model_copy(const ccv_cnnp_model_t* const super, void* const context); |
78 | |
79 | static void _ccv_cnnp_sequential_model_add_to_parameter_indices(ccv_cnnp_model_t* const super, const int index, ccv_array_t* const parameter_indices) |
80 | { |
81 | ccv_cnnp_sequential_model_t* const self = (ccv_cnnp_sequential_model_t*)super; |
82 | int i; |
83 | for (i = 0; i < self->sequence_size; i++) |
84 | ccv_cnnp_model_add_to_parameter_indices(self->sequence[i], index, parameter_indices); |
85 | } |
86 | |
87 | static void _ccv_cnnp_sequential_model_notify(const ccv_cnnp_model_t* const super, const int tag, void* const payload) |
88 | { |
89 | ccv_cnnp_sequential_model_t* const self = (ccv_cnnp_sequential_model_t*)super; |
90 | int i; |
91 | for (i = 0; i < self->sequence_size; i++) |
92 | ccv_cnnp_model_notify(self->sequence[i], tag, payload); |
93 | } |
94 | |
95 | static const ccv_cnnp_model_vtab_t ccv_cnnp_sequential_model_isa = { |
96 | .deinit = _ccv_cnnp_sequential_model_deinit, |
97 | .build = _ccv_cnnp_sequential_model_build, |
98 | .init_states = _ccv_cnnp_sequential_model_init_states, |
99 | .copy = _ccv_cnnp_sequential_model_copy, |
100 | .set_is_test = _ccv_cnnp_sequential_model_set_is_test, |
101 | .add_to_parameter_indices = _ccv_cnnp_sequential_model_add_to_parameter_indices, |
102 | .notify = _ccv_cnnp_sequential_model_notify, |
103 | }; |
104 | |
105 | KHASH_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; } } |
106 | |
107 | static ccv_cnnp_model_t* _ccv_cnnp_sequential_model_copy(const ccv_cnnp_model_t* const super, void* const context) |
108 | { |
109 | const ccv_cnnp_sequential_model_t* const self = (const ccv_cnnp_sequential_model_t*)super; |
110 | 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)); |
111 | sequential_model->super.isa = &ccv_cnnp_sequential_model_isa; |
112 | sequential_model->super.input_size = 1; |
113 | sequential_model->super.outputs = (ccv_nnc_tensor_symbol_t*)(sequential_model->sequence + self->sequence_size); |
114 | sequential_model->super.output_size = 1; |
115 | ccv_cnnp_model_copy_name(&sequential_model->super, self->super.name); |
116 | sequential_model->sequence_size = self->sequence_size; |
117 | int i; |
118 | khash_t(model)kh_model_t* model_map = context ? (khash_t(model)kh_model_t*)context : kh_init(model)kh_init_model(); |
119 | for (i = 0; i < self->sequence_size; i++) |
120 | { |
121 | ccv_cnnp_model_t* const sub_model = self->sequence[i]; |
122 | int ret; |
123 | 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); |
124 | ccv_cnnp_model_t* model_copy; |
125 | if (ret != 0) |
126 | model_copy = kh_val(model_map, k)((model_map)->vals[k]) = _ccv_cnnp_model_copy(sub_model, model_map); |
127 | else |
128 | model_copy = kh_val(model_map, k)((model_map)->vals[k]); |
129 | sequential_model->sequence[i] = model_copy; |
130 | } |
131 | if (!context) |
132 | kh_destroy(model, model_map)kh_destroy_model(model_map); |
133 | return (ccv_cnnp_model_t*)sequential_model; |
134 | } |
135 | |
136 | ccv_cnnp_model_t* ccv_cnnp_sequential_new(ccv_cnnp_model_t* const* const models, const int model_size, const char* const name) |
137 | { |
138 | 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", 138, __extension__ __PRETTY_FUNCTION__ ); })); |
139 | 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)); |
140 | sequential_model->super.isa = &ccv_cnnp_sequential_model_isa; |
141 | sequential_model->super.input_size = models[0]->input_size; |
142 | sequential_model->super.outputs = (ccv_nnc_tensor_symbol_t*)(sequential_model->sequence + model_size); |
143 | sequential_model->super.output_size = 1; |
144 | ccv_cnnp_model_copy_name(&sequential_model->super, name); |
145 | sequential_model->sequence_size = model_size; |
146 | memcpy(sequential_model->sequence, models, sizeof(ccv_cnnp_model_t*) * model_size); |
147 | return (ccv_cnnp_model_t*)sequential_model; |
148 | } |
149 | |
150 | typedef struct { |
151 | ccv_cnnp_model_t super; |
152 | // The name is similar to sequential model, but it is just topological sorted models. |
153 | int sequence_size; |
154 | ccv_cnnp_model_io_t sequence[1]; |
155 | } ccv_cnnp_functional_model_t; |
156 | |
157 | static void _ccv_cnnp_functional_model_deinit(ccv_cnnp_model_t* const super) |
158 | { |
159 | ccv_cnnp_functional_model_t* const self = (ccv_cnnp_functional_model_t*)super; |
160 | int i, j = 0, k; |
161 | for (i = 0; i < self->sequence_size; i++) |
162 | { |
163 | ccv_cnnp_model_t* const model = self->sequence[i]->model; |
164 | if (!model) |
165 | continue; |
166 | self->sequence[j++] = (ccv_cnnp_model_io_t)model; |
167 | // Go through all their IO to remove itself as model. |
168 | assert(model->io)((void) sizeof ((model->io) ? 1 : 0), __extension__ ({ if ( model->io) ; else __assert_fail ("model->io", "ccv_cnnp_model_core.c" , 168, __extension__ __PRETTY_FUNCTION__); })); |
169 | for (k = 0; k < model->io->rnum; k++) |
170 | { |
171 | 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))); |
172 | model_io->model = 0; |
173 | } |
174 | } |
175 | for (i = 0; i < j; i++) |
176 | ccv_cnnp_model_free((ccv_cnnp_model_t*)self->sequence[i]); |
177 | } |
178 | |
179 | static 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) |
180 | { |
181 | ccv_cnnp_functional_model_t* const self = (ccv_cnnp_functional_model_t*)super; |
182 | 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", 182, __extension__ __PRETTY_FUNCTION__ ); })); |
183 | 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", 183, __extension__ __PRETTY_FUNCTION__ ); })); |
184 | int i, j, k; |
185 | for (i = 0; i < self->super.input_size; i++) |
186 | 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. |
187 | ccv_array_t* input_symbols = ccv_array_new(sizeof(ccv_nnc_tensor_symbol_t), 1, 0); |
188 | ccv_array_t* parameter_indices = 0; |
189 | for (i = self->super.input_size; i < self->sequence_size; i++) |
190 | { |
191 | ccv_cnnp_model_t* const sub_model = self->sequence[i]->model; |
192 | ccv_array_clear(input_symbols); |
193 | const ccv_array_t* const incomings = self->sequence[i]->incomings; |
194 | for (j = 0; j < incomings->rnum; j++) |
195 | { |
196 | 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))); |
197 | if (CCV_CNNP_IS_MODEL_PARAMETER(input)((input)->param_ref != 0 || (input)->param_sel != 0)) |
198 | { |
199 | if (!parameter_indices) |
200 | parameter_indices = ccv_array_new(sizeof(int), 0, 0); |
201 | else |
202 | ccv_array_clear(parameter_indices); |
203 | const int param_sel = input->param_sel > 0 ? input->param_sel - 1 : input->param_sel; |
204 | 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", 204, __extension__ __PRETTY_FUNCTION__ ); })); |
205 | ccv_cnnp_model_add_to_parameter_indices(input->model, param_sel, parameter_indices); |
206 | 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" , 206, __extension__ __PRETTY_FUNCTION__); })); |
207 | const int param_ref = input->param_ref > 0 ? input->param_ref - 1 : input->param_ref; |
208 | 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", 208, __extension__ __PRETTY_FUNCTION__ ); })); |
209 | if (param_ref >= 0) |
210 | { |
211 | 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", 211, __extension__ __PRETTY_FUNCTION__ ); })); |
212 | 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)))); |
213 | ccv_array_push(input_symbols, ¶meter); |
214 | } else // Otherwise, all of them. |
215 | for (k = 0; k < parameter_indices->rnum; k++) |
216 | { |
217 | 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)))); |
218 | ccv_array_push(input_symbols, ¶meter); |
219 | } |
220 | } else { |
221 | for (k = 0; k < input->model->output_size; k++) |
222 | ccv_array_push(input_symbols, &input->outputs[k]); |
223 | } |
224 | } |
225 | // Go through each sub model to build the graph. |
226 | sub_model->data = self->super.data; |
227 | 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); |
228 | sub_model->data = 0; |
229 | } |
230 | ccv_array_free(input_symbols); |
231 | if (parameter_indices) |
232 | ccv_array_free(parameter_indices); |
233 | for (i = output_size, k = self->sequence_size - 1; k >= 0; k--) |
234 | { |
235 | ccv_cnnp_model_t* const sub_model = self->sequence[k]->model; |
236 | i -= sub_model->output_size; |
237 | if (i < 0) |
238 | break; |
239 | for (j = 0; j < sub_model->output_size; j++) |
240 | outputs[i + j] = self->sequence[k]->outputs[j]; |
241 | } |
242 | assert(i <= 0)((void) sizeof ((i <= 0) ? 1 : 0), __extension__ ({ if (i <= 0) ; else __assert_fail ("i <= 0", "ccv_cnnp_model_core.c" , 242, __extension__ __PRETTY_FUNCTION__); })); |
243 | } |
244 | |
245 | static 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) |
246 | { |
247 | ccv_cnnp_functional_model_t* const self = (ccv_cnnp_functional_model_t*)super; |
248 | int i; |
249 | for (i = self->super.input_size; i < self->sequence_size; i++) |
250 | ccv_cnnp_model_init_states(self->sequence[i]->model, graph, initializer, context); |
251 | } |
252 | |
253 | static 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) |
254 | { |
255 | ccv_cnnp_functional_model_t* const self = (ccv_cnnp_functional_model_t*)super; |
256 | int i; |
257 | for (i = self->super.input_size; i < self->sequence_size; i++) |
258 | ccv_cnnp_model_set_is_test(self->sequence[i]->model, is_test, updater, context); |
259 | } |
260 | |
261 | static void _ccv_cnnp_functional_model_add_to_parameter_indices(ccv_cnnp_model_t* const super, const int index, ccv_array_t* const parameter_indices) |
262 | { |
263 | ccv_cnnp_functional_model_t* const self = (ccv_cnnp_functional_model_t*)super; |
264 | int i; |
265 | for (i = self->super.input_size; i < self->sequence_size; i++) |
266 | ccv_cnnp_model_add_to_parameter_indices(self->sequence[i]->model, index, parameter_indices); |
267 | } |
268 | |
269 | static void _ccv_cnnp_functional_model_notify(const ccv_cnnp_model_t* const super, const int tag, void* const payload) |
270 | { |
271 | ccv_cnnp_functional_model_t* const self = (ccv_cnnp_functional_model_t*)super; |
272 | int i; |
273 | for (i = 0; i < self->sequence_size; i++) |
274 | { |
275 | const ccv_cnnp_model_t* const model = self->sequence[i]->model; |
276 | ccv_cnnp_model_notify(model, tag, payload); |
277 | } |
278 | } |
279 | |
280 | static ccv_cnnp_model_t* _ccv_cnnp_functional_model_copy(const ccv_cnnp_model_t* const super, void* const context); |
281 | |
282 | static const ccv_cnnp_model_vtab_t ccv_cnnp_functional_model_isa = { |
283 | .deinit = _ccv_cnnp_functional_model_deinit, |
284 | .build = _ccv_cnnp_functional_model_build, |
285 | .init_states = _ccv_cnnp_functional_model_init_states, |
286 | .copy = _ccv_cnnp_functional_model_copy, |
287 | .set_is_test = _ccv_cnnp_functional_model_set_is_test, |
288 | .add_to_parameter_indices = _ccv_cnnp_functional_model_add_to_parameter_indices, |
289 | .notify = _ccv_cnnp_functional_model_notify, |
290 | }; |
291 | |
292 |