| File: | nnc/ccv_cnnp_model_core.c |
| Warning: | line 487, 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 = 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 | |
| 37 | static 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 | |
| 45 | 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) |
| 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 | |
| 70 | 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) |
| 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 | |
| 78 | 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) |
| 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 | |
| 86 | static ccv_cnnp_model_t* _ccv_cnnp_sequential_model_copy(const ccv_cnnp_model_t* const super, void* const context); |
| 87 | |
| 88 | 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) |
| 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 | |
| 96 | static 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 | |
| 104 | static 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 | |
| 115 | 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; } } |
| 116 | |
| 117 | static 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 | |
| 146 | ccv_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 | |
| 161 | typedef 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 | |
| 168 | static 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 | |
| 175 | static 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 | |
| 182 | static 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 | |
| 211 | static 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 | |
| 217 | static 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 | |
| 223 | static 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 | |
| 229 | static 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 | |
| 235 | static ccv_cnnp_model_t* _ccv_cnnp_replicated_model_copy(const ccv_cnnp_model_t* const super, void* const context); |
| 236 | |
| 237 | static 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 | |
| 248 | ccv_cnnp_model_t* ccv_cnnp_replicated(ccv_cnnp_model_t* const model, const int count, const char* const name) |
| 249 | { |
| 250 | assert(model)((void) sizeof ((model) ? 1 : 0), __extension__ ({ if (model) ; else __assert_fail ("model", "ccv_cnnp_model_core.c", 250, __extension__ __PRETTY_FUNCTION__); })); |
| 251 | assert(count > 1)((void) sizeof ((count > 1) ? 1 : 0), __extension__ ({ if ( count > 1) ; else __assert_fail ("count > 1", "ccv_cnnp_model_core.c" , 251, __extension__ __PRETTY_FUNCTION__); })); |
| 252 | assert(model->input_size > 0)((void) sizeof ((model->input_size > 0) ? 1 : 0), __extension__ ({ if (model->input_size > 0) ; else __assert_fail ("model->input_size > 0" , "ccv_cnnp_model_core.c", 252, __extension__ __PRETTY_FUNCTION__ ); })); |
| 253 | assert(model->output_size > 0)((void) sizeof ((model->output_size > 0) ? 1 : 0), __extension__ ({ if (model->output_size > 0) ; else __assert_fail ("model->output_size > 0" , "ccv_cnnp_model_core.c", 253, __extension__ __PRETTY_FUNCTION__ ); })); |
| 254 | const int output_size = model->output_size * count; |
| 255 | ccv_cnnp_replicated_model_t* const replicated_model = (ccv_cnnp_replicated_model_t*)cccalloccalloc(1, sizeof(ccv_cnnp_replicated_model_t) + sizeof(ccv_nnc_tensor_symbol_t) * (output_size - 1)); |
| 256 | replicated_model->super.isa = &ccv_cnnp_replicated_model_isa; |
| 257 | replicated_model->super.input_size = model->input_size * count; |
| 258 | replicated_model->super.outputs = replicated_model->outputs; |
| 259 | replicated_model->super.output_size = output_size; |
| 260 | replicated_model->super.is_trainable = -1; |
| 261 | ccv_cnnp_model_copy_name(&replicated_model->super, name); |
| 262 | replicated_model->model = model; |
| 263 | replicated_model->count = count; |
| 264 | return (ccv_cnnp_model_t*)replicated_model; |
| 265 | } |
| 266 | |
| 267 | static ccv_cnnp_model_t* _ccv_cnnp_replicated_model_copy(const ccv_cnnp_model_t* const super, void* const context) |
| 268 | { |
| 269 | const ccv_cnnp_replicated_model_t* const self = (const ccv_cnnp_replicated_model_t*)super; |
| 270 | ccv_cnnp_model_t* const model_copy = _ccv_cnnp_model_copy(self->model, context); |
| 271 | return ccv_cnnp_replicated(model_copy, self->count, self->super.name); |
| 272 | } |
| 273 | |
| 274 | typedef 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 | |
| 284 | static 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 | |
| 307 | static 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 | |
| 315 | KHASH_MAP_INIT_INT64(io_node, ccv_array_t*)typedef struct kh_io_node_s { khint_t n_buckets, size, n_occupied , upper_bound; khint32_t *flags; khint64_t *keys; ccv_array_t * *vals; } kh_io_node_t; static inline __attribute__ ((__unused__ )) kh_io_node_t *kh_init_io_node(void) { return (kh_io_node_t *)calloc(1,sizeof(kh_io_node_t)); } static inline __attribute__ ((__unused__)) void kh_destroy_io_node(kh_io_node_t *h) { if (h) { free((void *)h->keys); free(h->flags); free((void *)h->vals); free(h); } } static inline __attribute__ ((__unused__ )) void kh_clear_io_node(kh_io_node_t *h) { if (h && h ->flags) { memset(h->flags, 0xaa, ((h->n_buckets) < 16? 1 : (h->n_buckets)>>4) * sizeof(khint32_t)); h-> size = h->n_occupied = 0; } } static inline __attribute__ ( (__unused__)) khint_t kh_get_io_node(const kh_io_node_t *h, khint64_t key) { if (h->n_buckets) { khint_t k, i, last, mask, step = 0; mask = h->n_buckets - 1; k = (khint32_t)((key)>> 33^(key)^(key)<<11); i = k & mask; last = i; while ( !((h->flags[i>>4]>>((i&0xfU)<<1))& 2) && (((h->flags[i>>4]>>((i&0xfU) <<1))&1) || !((h->keys[i]) == (key)))) { i = (i + (++step)) & mask; if (i == last) return h->n_buckets; } return ((h->flags[i>>4]>>((i&0xfU)<< 1))&3)? h->n_buckets : i; } else return 0; } static inline __attribute__ ((__unused__)) int kh_resize_io_node(kh_io_node_t *h, khint_t new_n_buckets) { khint32_t *new_flags = 0; khint_t j = 1; { (--(new_n_buckets), (new_n_buckets)|=(new_n_buckets )>>1, (new_n_buckets)|=(new_n_buckets)>>2, (new_n_buckets )|=(new_n_buckets)>>4, (new_n_buckets)|=(new_n_buckets) >>8, (new_n_buckets)|=(new_n_buckets)>>16, ++(new_n_buckets )); if (new_n_buckets < 4) new_n_buckets = 4; if (h->size >= (khint_t)(new_n_buckets * __ac_HASH_UPPER + 0.5)) j = 0 ; else { new_flags = (khint32_t*)malloc(((new_n_buckets) < 16? 1 : (new_n_buckets)>>4) * sizeof(khint32_t)); if ( !new_flags) return -1; memset(new_flags, 0xaa, ((new_n_buckets ) < 16? 1 : (new_n_buckets)>>4) * sizeof(khint32_t)) ; if (h->n_buckets < new_n_buckets) { khint64_t *new_keys = (khint64_t*)realloc((void *)h->keys,new_n_buckets * sizeof (khint64_t)); if (!new_keys) { free(new_flags); return -1; } h ->keys = new_keys; if (1) { ccv_array_t* *new_vals = (ccv_array_t **)realloc((void *)h->vals,new_n_buckets * sizeof(ccv_array_t *)); if (!new_vals) { free(new_flags); return -1; } h->vals = new_vals; } } } } if (j) { for (j = 0; j != h->n_buckets ; ++j) { if (((h->flags[j>>4]>>((j&0xfU)<< 1))&3) == 0) { khint64_t key = h->keys[j]; ccv_array_t * val; khint_t new_mask; new_mask = new_n_buckets - 1; if (1) val = h->vals[j]; (h->flags[j>>4]|=1ul<<(( j&0xfU)<<1)); while (1) { khint_t k, i, step = 0; k = (khint32_t)((key)>>33^(key)^(key)<<11); i = k & new_mask; while (!((new_flags[i>>4]>>((i&0xfU )<<1))&2)) i = (i + (++step)) & new_mask; (new_flags [i>>4]&=~(2ul<<((i&0xfU)<<1))); if ( i < h->n_buckets && ((h->flags[i>>4]>> ((i&0xfU)<<1))&3) == 0) { { khint64_t tmp = h-> keys[i]; h->keys[i] = key; key = tmp; } if (1) { ccv_array_t * tmp = h->vals[i]; h->vals[i] = val; val = tmp; } (h-> flags[i>>4]|=1ul<<((i&0xfU)<<1)); } else { h->keys[i] = key; if (1) h->vals[i] = val; break; } } } } if (h->n_buckets > new_n_buckets) { h->keys = ( khint64_t*)realloc((void *)h->keys,new_n_buckets * sizeof( khint64_t)); if (1) h->vals = (ccv_array_t**)realloc((void *)h->vals,new_n_buckets * sizeof(ccv_array_t*)); } free(h ->flags); h->flags = new_flags; h->n_buckets = new_n_buckets ; h->n_occupied = h->size; h->upper_bound = (khint_t )(h->n_buckets * __ac_HASH_UPPER + 0.5); } return 0; } static inline __attribute__ ((__unused__)) khint_t kh_put_io_node(kh_io_node_t *h, khint64_t key, int *ret) { khint_t x; if (h->n_occupied >= h->upper_bound) { if (h->n_buckets > (h->size <<1)) { if (kh_resize_io_node(h, h->n_buckets - 1) < 0) { *ret = -1; return h->n_buckets; } } else if (kh_resize_io_node (h, h->n_buckets + 1) < 0) { *ret = -1; return h->n_buckets ; } } { khint_t k, i, site, last, mask = h->n_buckets - 1, step = 0; x = site = h->n_buckets; k = (khint32_t)((key)>> 33^(key)^(key)<<11); i = k & mask; if (((h->flags [i>>4]>>((i&0xfU)<<1))&2)) x = i; else { last = i; while (!((h->flags[i>>4]>>((i& 0xfU)<<1))&2) && (((h->flags[i>>4] >>((i&0xfU)<<1))&1) || !((h->keys[i]) == (key)))) { if (((h->flags[i>>4]>>((i&0xfU )<<1))&1)) site = i; i = (i + (++step)) & mask; if (i == last) { x = site; break; } } if (x == h->n_buckets ) { if (((h->flags[i>>4]>>((i&0xfU)<< 1))&2) && site != h->n_buckets) x = site; else x = i; } } } if (((h->flags[x>>4]>>((x&0xfU )<<1))&2)) { h->keys[x] = key; (h->flags[x>> 4]&=~(3ul<<((x&0xfU)<<1))); ++h->size; ++h->n_occupied; *ret = 1; } else if (((h->flags[x>> 4]>>((x&0xfU)<<1))&1)) { h->keys[x] = key ; (h->flags[x>>4]&=~(3ul<<((x&0xfU)<< 1))); ++h->size; *ret = 2; } else *ret = 0; return x; } static inline __attribute__ ((__unused__)) void kh_del_io_node(kh_io_node_t *h, khint_t x) { if (x != h->n_buckets && !((h-> flags[x>>4]>>((x&0xfU)<<1))&3)) { ( h->flags[x>>4]|=1ul<<((x&0xfU)<<1)); --h->size; } } |
| 316 | |
| 317 | typedef 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 | |
| 323 | static 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 | |
| 331 | 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) |
| 332 | { |
| 333 | ccv_cnnp_functional_model_t* const self = (ccv_cnnp_functional_model_t*)super; |
| 334 | PRINT(CCV_CLI_VERBOSE, "[cnnp_functional_model_build] 1. %p, input_size: %d, output_size: %d\n", self, input_size, output_size)do { if ((CCV_CLI_VERBOSE & ccv_cli_get_output_levels())) { printf("[cnnp_functional_model_build] 1. %p, input_size: %d, output_size: %d\n" , self, input_size, output_size); fflush(stdout); } } while ( 0); |
| 335 | assert(self->super.input_size == input_size)((void) sizeof ((self->super.input_size == input_size) ? 1 : 0), __extension__ ({ if (self->super.input_size == input_size ) ; else __assert_fail ("self->super.input_size == input_size" , "ccv_cnnp_model_core.c", 335, __extension__ __PRETTY_FUNCTION__ ); })); |
| 336 | assert(self->super.output_size == output_size)((void) sizeof ((self->super.output_size == output_size) ? 1 : 0), __extension__ ({ if (self->super.output_size == output_size ) ; else __assert_fail ("self->super.output_size == output_size" , "ccv_cnnp_model_core.c", 336, __extension__ __PRETTY_FUNCTION__ ); })); |
| 337 | int i, j, k; |
| 338 | for (i = 0; i < self->super.input_size; i++) |
| 339 | self->sequence[i]->outputs[0] = self->sequence[i]->model->outputs[0] = inputs[i]; // Assigning the output symbol of input layer to be the input symbol. |
| 340 | ccv_array_t* input_symbols = ccv_array_new(sizeof(ccv_nnc_tensor_symbol_t), 1, 0); |
| 341 | ccv_array_t* parameter_indices = 0; |
| 342 | khash_t(io_node)kh_io_node_t* io_node_map = kh_init(io_node)kh_init_io_node(); |
| 343 | for (i = self->super.input_size; i < self->sequence_size; i++) |
| 344 | { |
| 345 | ccv_cnnp_model_t* const sub_model = self->sequence[i]->model; |
| 346 | ccv_array_clear(input_symbols); |
| 347 | const ccv_array_t* const incomings = self->sequence[i]->incomings; |
| 348 | if (incomings) |
| 349 | for (j = 0; j < incomings->rnum; j++) |
| 350 | { |
| 351 | const ccv_cnnp_model_io_t input = *(ccv_cnnp_model_io_t*)ccv_array_get(incomings, j)((void*)(((char*)((incomings)->data)) + (size_t)(incomings )->rsize * (size_t)(j))); |
| 352 | if (CCV_CNNP_IS_MODEL_PARAMETER(input)((input)->param_ref != 0 || (input)->param_sel != 0)) |
| 353 | { |
| 354 | if (!parameter_indices) |
| 355 | parameter_indices = ccv_array_new(sizeof(int), 0, 0); |
| 356 | else |
| 357 | ccv_array_clear(parameter_indices); |
| 358 | const int param_sel = input->param_sel > 0 ? input->param_sel - 1 : input->param_sel; |
| 359 | assert(input->param_sel != 0)((void) sizeof ((input->param_sel != 0) ? 1 : 0), __extension__ ({ if (input->param_sel != 0) ; else __assert_fail ("input->param_sel != 0" , "ccv_cnnp_model_core.c", 359, __extension__ __PRETTY_FUNCTION__ ); })); |
| 360 | ccv_cnnp_model_add_to_parameter_indices(input->model, param_sel, parameter_indices); |
| 361 | assert(parameter_indices->rnum > 0)((void) sizeof ((parameter_indices->rnum > 0) ? 1 : 0), __extension__ ({ if (parameter_indices->rnum > 0) ; else __assert_fail ("parameter_indices->rnum > 0", "ccv_cnnp_model_core.c" , 361, __extension__ __PRETTY_FUNCTION__); })); |
| 362 | const int param_ref = input->param_ref > 0 ? input->param_ref - 1 : input->param_ref; |
| 363 | assert(input->param_ref != 0)((void) sizeof ((input->param_ref != 0) ? 1 : 0), __extension__ ({ if (input->param_ref != 0) ; else __assert_fail ("input->param_ref != 0" , "ccv_cnnp_model_core.c", 363, __extension__ __PRETTY_FUNCTION__ ); })); |
| 364 | if (param_ref >= 0) |
| 365 | { |
| 366 | assert(param_ref < parameter_indices->rnum)((void) sizeof ((param_ref < parameter_indices->rnum) ? 1 : 0), __extension__ ({ if (param_ref < parameter_indices ->rnum) ; else __assert_fail ("param_ref < parameter_indices->rnum" , "ccv_cnnp_model_core.c", 366, __extension__ __PRETTY_FUNCTION__ ); })); |
| 367 | const ccv_nnc_tensor_symbol_t parameter = ccv_cnnp_parameter_from_indice(super, *(int*)ccv_array_get(parameter_indices, param_ref)((void*)(((char*)((parameter_indices)->data)) + (size_t)(parameter_indices )->rsize * (size_t)(param_ref)))); |
| 368 | ccv_array_push(input_symbols, ¶meter); |
| 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, ¶meter); |
| 374 | } |
| 375 | } else { |
| 376 | for (k = 0; k < input->model->output_size; k++) |
| 377 | ccv_array_push(input_symbols, &input->outputs[k]); |
| 378 | } |
| 379 | } |
| 380 | // Go through each sub model to build the graph. |
| 381 | ccv_array_t* nodes; |
| 382 | ccv_functional_model_build_node_hook_t hook; |
| 383 | const ccv_array_t* const dependencies = self->sequence[i]->dependencies; |
| 384 | if ((dependencies && dependencies->rnum > 0) || self->sequence[i]->dependents > 0) |
| 385 | { |
| 386 | int ret; |
| 387 | khiter_t k = kh_put(io_node, io_node_map, (uint64_t)(uintptr_t)self->sequence[i], &ret)kh_put_io_node(io_node_map, (uint64_t)(uintptr_t)self->sequence [i], &ret); |
| 388 | if (ret != 0) |
| 389 | nodes = kh_val(io_node_map, k)((io_node_map)->vals[k]) = ccv_array_new(sizeof(ccv_nnc_graph_exec_symbol_t), 1, 0); |
| 390 | else |
| 391 | nodes = kh_val(io_node_map, k)((io_node_map)->vals[k]); |
| 392 | hook.nodes = nodes; |
| 393 | hook.previous_context = ccv_nnc_graph_exec_symbol_new_hook(graph, _ccv_cnnp_functional_model_build_node_new, &hook, &hook.previous_func); |
| 394 | } |
| 395 | sub_model->data = self->super.data; |
| 396 | ccv_cnnp_model_build(sub_model, graph, (ccv_nnc_tensor_symbol_t*)ccv_array_get(input_symbols, 0)((void*)(((char*)((input_symbols)->data)) + (size_t)(input_symbols )->rsize * (size_t)(0))), input_symbols->rnum, self->sequence[i]->outputs, sub_model->output_size); |
| 397 | if ((dependencies && dependencies->rnum > 0) || self->sequence[i]->dependents > 0) |
| 398 | { |
| 399 | ccv_nnc_graph_exec_symbol_new_hook(graph, hook.previous_func, hook.previous_context, 0); |
| 400 | if (dependencies) |
| 401 | for (j = 0; j < dependencies->rnum; j++) |
| 402 | { |
| 403 | const ccv_cnnp_model_io_t dependency = *(ccv_cnnp_model_io_t*)ccv_array_get(dependencies, j)((void*)(((char*)((dependencies)->data)) + (size_t)(dependencies )->rsize * (size_t)(j))); |
| 404 | khiter_t k = kh_get(io_node, io_node_map, (uint64_t)(uintptr_t)dependency)kh_get_io_node(io_node_map, (uint64_t)(uintptr_t)dependency); |
| 405 | if (k == kh_end(io_node_map)((io_node_map)->n_buckets)) |
| 406 | continue; |
| 407 | const ccv_array_t* const dependency_nodes = kh_val(io_node_map, k)((io_node_map)->vals[k]); |
| 408 | int x, y; |
| 409 | for (y = 0; y < dependency_nodes->rnum; y++) |
| 410 | for (x = 0; x < nodes->rnum; x++) |
| 411 | ccv_nnc_graph_exec_symbol_concat(graph, *(ccv_nnc_graph_exec_symbol_t*)ccv_array_get(dependency_nodes, y)((void*)(((char*)((dependency_nodes)->data)) + (size_t)(dependency_nodes )->rsize * (size_t)(y))), *(ccv_nnc_graph_exec_symbol_t*)ccv_array_get(nodes, x)((void*)(((char*)((nodes)->data)) + (size_t)(nodes)->rsize * (size_t)(x)))); |
| 412 | } |
| 413 | } |
| 414 | sub_model->data = 0; |
| 415 | } |
| 416 | khiter_t it; |
| 417 | for (it = kh_begin(io_node_map)(khint_t)(0); it != kh_end(io_node_map)((io_node_map)->n_buckets); ++it) |
| 418 | { |
| 419 | if (!kh_exist(io_node_map, it)(!(((io_node_map)->flags[(it)>>4]>>(((it)& 0xfU)<<1))&3))) |
| 420 | continue; |
| 421 | ccv_array_t* const nodes = kh_val(io_node_map, it)((io_node_map)->vals[it]); |
| 422 | ccv_array_free(nodes); |
| 423 | } |
| 424 | kh_destroy(io_node, io_node_map)kh_destroy_io_node(io_node_map); |
| 425 | ccv_array_free(input_symbols); |
| 426 | if (parameter_indices) |
| 427 | ccv_array_free(parameter_indices); |
| 428 | for (i = 0, k = 0; k < self->model_output_size; k++) |
| 429 | { |
| 430 | ccv_cnnp_model_t* const sub_model = self->sequence[self->model_outputs[k]]->model; |
| 431 | for (j = 0; j < sub_model->output_size; j++) |
| 432 | outputs[i + j] = self->sequence[self->model_outputs[k]]->outputs[j]; |
| 433 | i += sub_model->output_size; |
| 434 | } |
| 435 | assert(i == output_size)((void) sizeof ((i == output_size) ? 1 : 0), __extension__ ({ if (i == output_size) ; else __assert_fail ("i == output_size" , "ccv_cnnp_model_core.c", 435, __extension__ __PRETTY_FUNCTION__ ); })); |
| 436 | PRINT(CCV_CLI_VERBOSE, "[cnnp_functional_model_build] 2. %p\n", self)do { if ((CCV_CLI_VERBOSE & ccv_cli_get_output_levels())) { printf("[cnnp_functional_model_build] 2. %p\n", self); fflush (stdout); } } while (0); |
| 437 | } |
| 438 | |
| 439 | 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) |
| 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 | |
| 447 | 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) |
| 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 | |
| 455 | 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) |
| 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 | |
| 463 | static 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 | |
| 474 | static ccv_cnnp_model_t* _ccv_cnnp_functional_model_copy(const ccv_cnnp_model_t* const super, void* const context); |
| 475 | |
| 476 | static 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 | |
| 487 |