| File: | nnc/ccv_cnnp_model_core.c |
| Warning: | line 115, column 1 Array access (via field 'flags') results in a null pointer dereference |
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 | // The model's outputs, it is different from super.output_size, as latter is for actual tensor symbols. | |||
| 164 | int model_output_size; | |||
| 165 | // The name is similar to sequential model, but it is just topological sorted models. | |||
| 166 | int sequence_size; | |||
| 167 | int* model_outputs; // Which model, as in sequences, have some outputs. | |||
| 168 | ccv_cnnp_model_io_t sequence[1]; | |||
| 169 | } ccv_cnnp_functional_model_t; | |||
| 170 | ||||
| 171 | static void _ccv_cnnp_functional_model_deinit(ccv_cnnp_model_t* const super) | |||
| 172 | { | |||
| 173 | ccv_cnnp_functional_model_t* const self = (ccv_cnnp_functional_model_t*)super; | |||
| 174 | int i, j = 0, k; | |||
| 175 | for (i = 0; i < self->sequence_size; i++) | |||
| 176 | { | |||
| 177 | ccv_cnnp_model_t* const model = self->sequence[i]->model; | |||
| 178 | if (!model || model->deinit_state) | |||
| 179 | continue; | |||
| 180 | self->sequence[j++] = (ccv_cnnp_model_io_t)model; | |||
| 181 | // Go through all their IO to remove itself as model. | |||
| 182 | assert(model->io)((void) sizeof ((model->io) ? 1 : 0), __extension__ ({ if ( model->io) ; else __assert_fail ("model->io", "ccv_cnnp_model_core.c" , 182, __extension__ __PRETTY_FUNCTION__); })); | |||
| 183 | for (k = 0; k < model->io->rnum; k++) | |||
| 184 | { | |||
| 185 | 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))); | |||
| 186 | model_io->model = 0; | |||
| 187 | } | |||
| 188 | } | |||
| 189 | for (i = 0; i < j; i++) | |||
| 190 | ccv_cnnp_model_deinit((ccv_cnnp_model_t*)self->sequence[i]); | |||
| 191 | self->sequence_size = j; | |||
| 192 | } | |||
| 193 | ||||
| 194 | static void _ccv_cnnp_functional_model_dealloc(ccv_cnnp_model_t* const super) | |||
| 195 | { | |||
| 196 | ccv_cnnp_functional_model_t* const self = (ccv_cnnp_functional_model_t*)super; | |||
| 197 | int i; | |||
| 198 | for (i = 0; i < self->sequence_size; i++) | |||
| 199 | ccv_cnnp_model_free((ccv_cnnp_model_t*)self->sequence[i]); | |||
| 200 | } | |||
| 201 | ||||
| 202 | 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; } } | |||
| 203 | ||||
| 204 | typedef struct { | |||
| 205 | ccv_array_t* nodes; | |||
| 206 | ccv_nnc_graph_exec_symbol_new_hook_f previous_func; | |||
| 207 | void* previous_context; | |||
| 208 | } ccv_functional_model_build_node_hook_t; | |||
| 209 | ||||
| 210 | 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) | |||
| 211 | { | |||
| 212 | ccv_functional_model_build_node_hook_t* const hook = (ccv_functional_model_build_node_hook_t*)context; | |||
| 213 | ccv_array_push(hook->nodes, &symbol); | |||
| 214 | if (hook->previous_func) | |||
| 215 | hook->previous_func(hook->previous_context, symbol, cmd, inputs, input_size, outputs, output_size, name); | |||
| 216 | } | |||
| 217 | ||||
| 218 | 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) | |||
| 219 | { | |||
| 220 | ccv_cnnp_functional_model_t* const self = (ccv_cnnp_functional_model_t*)super; | |||
| 221 | 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); | |||
| 222 | 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", 222, __extension__ __PRETTY_FUNCTION__ ); })); | |||
| 223 | 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", 223, __extension__ __PRETTY_FUNCTION__ ); })); | |||
| 224 | int i, j, k; | |||
| 225 | for (i = 0; i < self->super.input_size; i++) | |||
| 226 | 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. | |||
| 227 | ccv_array_t* input_symbols = ccv_array_new(sizeof(ccv_nnc_tensor_symbol_t), 1, 0); | |||
| 228 | ccv_array_t* parameter_indices = 0; | |||
| 229 | khash_t(io_node)kh_io_node_t* io_node_map = kh_init(io_node)kh_init_io_node(); | |||
| 230 | for (i = self->super.input_size; i < self->sequence_size; i++) | |||
| 231 | { | |||
| 232 | ccv_cnnp_model_t* const sub_model = self->sequence[i]->model; | |||
| 233 | ccv_array_clear(input_symbols); | |||
| 234 | const ccv_array_t* const incomings = self->sequence[i]->incomings; | |||
| 235 | if (incomings) | |||
| 236 | for (j = 0; j < incomings->rnum; j++) | |||
| 237 | { | |||
| 238 | 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))); | |||
| 239 | if (CCV_CNNP_IS_MODEL_PARAMETER(input)((input)->param_ref != 0 || (input)->param_sel != 0)) | |||
| 240 | { | |||
| 241 | if (!parameter_indices) | |||
| 242 | parameter_indices = ccv_array_new(sizeof(int), 0, 0); | |||
| 243 | else | |||
| 244 | ccv_array_clear(parameter_indices); | |||
| 245 | const int param_sel = input->param_sel > 0 ? input->param_sel - 1 : input->param_sel; | |||
| 246 | 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", 246, __extension__ __PRETTY_FUNCTION__ ); })); | |||
| 247 | ccv_cnnp_model_add_to_parameter_indices(input->model, param_sel, parameter_indices); | |||
| 248 | 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" , 248, __extension__ __PRETTY_FUNCTION__); })); | |||
| 249 | const int param_ref = input->param_ref > 0 ? input->param_ref - 1 : input->param_ref; | |||
| 250 | 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", 250, __extension__ __PRETTY_FUNCTION__ ); })); | |||
| 251 | if (param_ref >= 0) | |||
| 252 | { | |||
| 253 | 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", 253, __extension__ __PRETTY_FUNCTION__ ); })); | |||
| 254 | 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)))); | |||
| 255 | ccv_array_push(input_symbols, ¶meter); | |||
| 256 | } else // Otherwise, all of them. | |||
| 257 | for (k = 0; k < parameter_indices->rnum; k++) | |||
| 258 | { | |||
| 259 | 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)))); | |||
| 260 | ccv_array_push(input_symbols, ¶meter); | |||
| 261 | } | |||
| 262 | } else { | |||
| 263 | for (k = 0; k < input->model->output_size; k++) | |||
| 264 | ccv_array_push(input_symbols, &input->outputs[k]); | |||
| 265 | } | |||
| 266 | } | |||
| 267 | // Go through each sub model to build the graph. | |||
| 268 | ccv_array_t* nodes; | |||
| 269 | ccv_functional_model_build_node_hook_t hook; | |||
| 270 | const ccv_array_t* const dependencies = self->sequence[i]->dependencies; | |||
| 271 | if ((dependencies && dependencies->rnum > 0) || self->sequence[i]->dependents > 0) | |||
| 272 | { | |||
| 273 | int ret; | |||
| 274 | 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); | |||
| 275 | if (ret != 0) | |||
| 276 | nodes = kh_val(io_node_map, k)((io_node_map)->vals[k]) = ccv_array_new(sizeof(ccv_nnc_graph_exec_symbol_t), 1, 0); | |||
| 277 | else | |||
| 278 | nodes = kh_val(io_node_map, k)((io_node_map)->vals[k]); | |||
| 279 | hook.nodes = nodes; | |||
| 280 | hook.previous_context = ccv_nnc_graph_exec_symbol_new_hook(graph, _ccv_cnnp_functional_model_build_node_new, &hook, &hook.previous_func); | |||
| 281 | } | |||
| 282 | sub_model->data = self->super.data; | |||
| 283 | 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); | |||
| 284 | if ((dependencies && dependencies->rnum > 0) || self->sequence[i]->dependents > 0) | |||
| 285 | { | |||
| 286 | ccv_nnc_graph_exec_symbol_new_hook(graph, hook.previous_func, hook.previous_context, 0); | |||
| 287 | if (dependencies) | |||
| 288 | for (j = 0; j < dependencies->rnum; j++) | |||
| 289 | { | |||
| 290 | 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))); | |||
| 291 | 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); | |||
| 292 | if (k == kh_end(io_node_map)((io_node_map)->n_buckets)) | |||
| 293 | continue; | |||
| 294 | const ccv_array_t* const dependency_nodes = kh_val(io_node_map, k)((io_node_map)->vals[k]); | |||
| 295 | int x, y; | |||
| 296 | for (y = 0; y < dependency_nodes->rnum; y++) | |||
| 297 | for (x = 0; x < nodes->rnum; x++) | |||
| 298 | 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)))); | |||
| 299 | } | |||
| 300 | } | |||
| 301 | sub_model->data = 0; | |||
| 302 | } | |||
| 303 | khiter_t it; | |||
| 304 | for (it = kh_begin(io_node_map)(khint_t)(0); it != kh_end(io_node_map)((io_node_map)->n_buckets); ++it) | |||
| 305 | { | |||
| 306 | if (!kh_exist(io_node_map, it)(!(((io_node_map)->flags[(it)>>4]>>(((it)& 0xfU)<<1))&3))) | |||
| 307 | continue; | |||
| 308 | ccv_array_t* const nodes = kh_val(io_node_map, it)((io_node_map)->vals[it]); | |||
| 309 | ccv_array_free(nodes); | |||
| 310 | } | |||
| 311 | kh_destroy(io_node, io_node_map)kh_destroy_io_node(io_node_map); | |||
| 312 | ccv_array_free(input_symbols); | |||
| 313 | if (parameter_indices) | |||
| 314 | ccv_array_free(parameter_indices); | |||
| 315 | for (i = 0, k = 0; k < self->model_output_size; k++) | |||
| 316 | { | |||
| 317 | ccv_cnnp_model_t* const sub_model = self->sequence[self->model_outputs[k]]->model; | |||
| 318 | for (j = 0; j < sub_model->output_size; j++) | |||
| 319 | outputs[i + j] = self->sequence[self->model_outputs[k]]->outputs[j]; | |||
| 320 | i += sub_model->output_size; | |||
| 321 | } | |||
| 322 | 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", 322, __extension__ __PRETTY_FUNCTION__ ); })); | |||
| 323 | 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); | |||
| 324 | } | |||
| 325 | ||||
| 326 | 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) | |||
| 327 | { | |||
| 328 | ccv_cnnp_functional_model_t* const self = (ccv_cnnp_functional_model_t*)super; | |||
| 329 | int i; | |||
| 330 | for (i = self->super.input_size; i < self->sequence_size; i++) | |||
| 331 | ccv_cnnp_model_init_states(self->sequence[i]->model, graph, initializer, context); | |||
| 332 | } | |||
| 333 | ||||
| 334 | 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) | |||
| 335 | { | |||
| 336 | ccv_cnnp_functional_model_t* const self = (ccv_cnnp_functional_model_t*)super; | |||
| 337 | int i; | |||
| 338 | for (i = self->super.input_size; i < self->sequence_size; i++) | |||
| 339 | ccv_cnnp_model_set_is_test(self->sequence[i]->model, is_test, updater, context); | |||
| 340 | } | |||
| 341 | ||||
| 342 | 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) | |||
| 343 | { | |||
| 344 | ccv_cnnp_functional_model_t* const self = (ccv_cnnp_functional_model_t*)super; | |||
| 345 | int i; | |||
| 346 | for (i = self->super.input_size; i < self->sequence_size; i++) | |||
| 347 | ccv_cnnp_model_add_to_parameter_indices(self->sequence[i]->model, index, parameter_indices); | |||
| 348 | } | |||
| 349 | ||||
| 350 | static void _ccv_cnnp_functional_model_notify(const ccv_cnnp_model_t* const super, const int tag, void* const payload) | |||
| 351 | { | |||
| 352 | ccv_cnnp_functional_model_t* const self = (ccv_cnnp_functional_model_t*)super; | |||
| 353 | int i; | |||
| 354 | for (i = 0; i < self->sequence_size; i++) | |||
| 355 | { | |||
| 356 | const ccv_cnnp_model_t* const model = self->sequence[i]->model; | |||
| 357 | ccv_cnnp_model_notify(model, tag, payload); | |||
| 358 | } | |||
| 359 | } | |||
| 360 | ||||
| 361 | static ccv_cnnp_model_t* _ccv_cnnp_functional_model_copy(const ccv_cnnp_model_t* const super, void* const context); | |||
| 362 | ||||
| 363 | static const ccv_cnnp_model_vtab_t ccv_cnnp_functional_model_isa = { | |||
| 364 | .deinit = _ccv_cnnp_functional_model_deinit, | |||
| 365 | .dealloc = _ccv_cnnp_functional_model_dealloc, | |||
| 366 | .build = _ccv_cnnp_functional_model_build, | |||
| 367 | .init_states = _ccv_cnnp_functional_model_init_states, | |||
| 368 | .copy = _ccv_cnnp_functional_model_copy, | |||
| 369 | .set_is_test = _ccv_cnnp_functional_model_set_is_test, | |||
| 370 | .add_to_parameter_indices = _ccv_cnnp_functional_model_add_to_parameter_indices, | |||
| 371 | .notify = _ccv_cnnp_functional_model_notify, | |||
| 372 | }; | |||
| 373 | ||||
| 374 | KHASH_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; } } | |||
| 375 | ||||
| 376 | static ccv_cnnp_model_t* _ccv_cnnp_functional_model_copy(const ccv_cnnp_model_t* const super, void* const context) | |||
| 377 | { | |||
| 378 | const ccv_cnnp_functional_model_t* const self = (const ccv_cnnp_functional_model_t*)super; | |||
| 379 | 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); | |||
| 380 | functional_model->super.isa = &ccv_cnnp_functional_model_isa; | |||
| 381 | functional_model->super.outputs = (ccv_nnc_tensor_symbol_t*)(functional_model->sequence + self->sequence_size); | |||
| 382 | functional_model->super.output_size = self->super.output_size; | |||
| 383 | functional_model->super.input_size = self->super.input_size; | |||
| 384 | ccv_cnnp_model_copy_name(&functional_model->super, self->super.name); | |||
| 385 | functional_model->sequence_size = self->sequence_size; | |||
| 386 | functional_model->model_output_size = self->model_output_size; | |||
| 387 | functional_model->model_outputs = (int*)(functional_model->super.outputs + functional_model->super.output_size); | |||
| 388 | memcpy(functional_model->model_outputs, self->model_outputs, sizeof(int) * self->model_output_size); | |||
| 389 | // Now the difficult part, copy over the model_io. | |||
| 390 | khash_t(model_io)kh_model_io_t* model_io_map = kh_init(model_io)kh_init_model_io(); | |||
| 391 | khash_t(model)kh_model_t* model_map = context ? (khash_t(model)kh_model_t*)context : kh_init(model)kh_init_model(); | |||
| ||||
| 392 | int i, j; | |||
| 393 | for (i = 0; i < self->sequence_size; i++) | |||
| 394 | { | |||
| 395 | const ccv_cnnp_model_t* const sub_model = self->sequence[i]->model; | |||
| 396 | int ret; | |||
| 397 | 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); | |||
| 398 | ccv_cnnp_model_t* model_copy; | |||
| 399 | if (ret != 0) | |||
| 400 | model_copy = kh_val(model_map, k)((model_map)->vals[k]) = _ccv_cnnp_model_copy(sub_model, model_map); | |||
| 401 | else | |||
| 402 | model_copy = kh_val(model_map, k)((model_map)->vals[k]); | |||
| 403 | 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); | |||
| 404 | model_io->param_ref = 0; | |||
| 405 | model_io->param_sel = 0; | |||
| 406 | model_io->visit = 0; | |||
| 407 | model_io->model = model_copy; | |||
| 408 | model_io->dependencies = 0; | |||
| 409 | model_io->dependents = 0; | |||
| 410 | model_io->incomings = 0; | |||
| 411 | model_io->outgoings = 0; | |||
| 412 | model_io->outputs = (ccv_nnc_tensor_symbol_t*)(model_io + 1); | |||
| 413 | if (!model_copy->io) | |||
| 414 | model_copy->io = ccv_array_new(sizeof(ccv_cnnp_model_io_t), 1, 0); | |||
| 415 | ccv_array_push(model_copy->io, &model_io); | |||
| 416 | 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); | |||
| 417 | kh_val(model_io_map, k)((model_io_map)->vals[k]) = functional_model->sequence[i]; | |||
| 418 | } | |||
| 419 | for (i = self->super.input_size; i < self->sequence_size; i++) | |||
| 420 | { | |||
| 421 | if (self->sequence[i]->incomings) | |||
| 422 | for (j = 0; j < self->sequence[i]->incomings->rnum; j++) | |||
| 423 | { | |||
| 424 | 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))); | |||
| 425 | 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. | |||
| 426 | { | |||
| 427 | int ret; | |||
| 428 | 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); | |||
| 429 | if (ret != 0) | |||
| 430 | { | |||
| 431 | // The model may not exist on the map due to wrapping (it is inside another sequential or functional model). | |||
| 432 | 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); | |||
| 433 | 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", 433, __extension__ __PRETTY_FUNCTION__); })); | |||
| 434 | ccv_cnnp_model_t* const model_copy = kh_val(model_map, m)((model_map)->vals[m]); | |||
| 435 | ccv_cnnp_model_io_t model_io = ccmallocmalloc(sizeof(struct ccv_cnnp_model_io_s)); | |||
| 436 | model_io->param_ref = input->param_ref; | |||
| 437 | model_io->param_sel = input->param_sel; | |||
| 438 | model_io->visit = 0; | |||
| 439 | model_io->model = model_copy; | |||
| 440 | model_io->incomings = 0; | |||
| 441 | model_io->dependencies = 0; | |||
| 442 | model_io->dependents = 0; | |||
| 443 | model_io->outgoings = 0; | |||
| 444 | model_io->outputs = 0; | |||
| 445 | if (!model_copy->io) | |||
| 446 | model_copy->io = ccv_array_new(sizeof(ccv_cnnp_model_io_t), 1, 0); | |||
| 447 | ccv_array_push(model_copy->io, &model_io); | |||
| 448 | kh_val(model_io_map, k)((model_io_map)->vals[k]) = model_io; | |||
| 449 | if (input->outgoings) | |||
| 450 | { | |||
| 451 | model_io->outgoings = ccv_array_new(sizeof(ccv_cnnp_model_io_t), input->outgoings->rnum, 0); | |||
| 452 | int x; | |||
| 453 | for (x = 0; x < input->outgoings->rnum; x++) | |||
| 454 | { | |||
| 455 | 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))))); | |||
| 456 | 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" , 456, __extension__ __PRETTY_FUNCTION__); })); | |||
| 457 | ccv_cnnp_model_io_t outgoing_io = kh_val(model_io_map, k)((model_io_map)->vals[k]); | |||
| 458 | ccv_array_push(model_io->outgoings, &outgoing_io); | |||
| 459 | } | |||
| 460 | } | |||
| 461 | } | |||
| 462 | } | |||
| 463 | } | |||
| 464 | } | |||
| 465 | if (!context) | |||
| 466 | kh_destroy(model, model_map)kh_destroy_model(model_map); | |||
| 467 | for (i = 0; i < self->sequence_size; i++) | |||
| 468 | { | |||
| 469 | const ccv_cnnp_model_io_t model_io = self->sequence[i]; | |||
| 470 | ccv_cnnp_model_io_t model_io_copy = functional_model->sequence[i]; | |||
| 471 | model_io_copy->param_ref = model_io->param_ref; | |||
| 472 | model_io_copy->param_sel = model_io->param_sel; | |||
| 473 | if (model_io->incomings) | |||
| 474 | { | |||
| 475 | model_io_copy->incomings = ccv_array_new(sizeof(ccv_cnnp_model_io_t), model_io->incomings->rnum, 0); | |||
| 476 | for (j = 0; j < model_io->incomings->rnum; j++) | |||
| 477 | { | |||
| 478 | 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))))); | |||
| 479 | 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" , 479, __extension__ __PRETTY_FUNCTION__); })); | |||
| 480 | ccv_cnnp_model_io_t input_io = kh_val(model_io_map, k)((model_io_map)->vals[k]); | |||
| 481 | ccv_array_push(model_io_copy->incomings, &input_io); | |||
| 482 | } | |||
| 483 | } | |||
| 484 | if (model_io->dependencies) | |||
| 485 | { | |||
| 486 | model_io_copy->dependencies = ccv_array_new(sizeof(ccv_cnnp_model_io_t), model_io->dependencies->rnum, 0); | |||
| 487 | for (j = 0; j < model_io->dependencies->rnum; j++) | |||
| 488 | { | |||
| 489 | 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)))) ); | |||
| 490 | 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" , 490, __extension__ __PRETTY_FUNCTION__); })); | |||
| 491 | ccv_cnnp_model_io_t input_io = kh_val(model_io_map, k)((model_io_map)->vals[k]); | |||
| 492 | ccv_array_push(model_io_copy->dependencies, &input_io); | |||
| 493 | } | |||
| 494 | } | |||
| 495 | model_io_copy->dependents = model_io->dependents; | |||
| 496 | if (model_io->outgoings) | |||
| 497 | { | |||
| 498 | model_io_copy->outgoings = ccv_array_new(sizeof(ccv_cnnp_model_io_t), model_io->outgoings->rnum, 0); | |||
| 499 | for (j = 0; j < model_io->outgoings->rnum; j++) | |||
| 500 | { | |||
| 501 | 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))))); | |||
| 502 | 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" , 502, __extension__ __PRETTY_FUNCTION__); })); | |||
| 503 | ccv_cnnp_model_io_t outgoing_io = kh_val(model_io_map, k)((model_io_map)->vals[k]); | |||
| 504 | ccv_array_push(model_io_copy->outgoings, &outgoing_io); | |||
| 505 | } | |||
| 506 | } | |||
| 507 | } | |||
| 508 | kh_destroy(model_io, model_io_map)kh_destroy_model_io(model_io_map); | |||
| 509 | return (ccv_cnnp_model_t*)functional_model; | |||
| 510 | } | |||
| 511 | ||||
| 512 | ccv_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) | |||
| 513 | { | |||
| 514 | 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", 514, __extension__ __PRETTY_FUNCTION__ ); })); | |||
| 515 | // Do topological sort. | |||
| 516 | ccv_array_t* const reverse_top = ccv_array_new(sizeof(ccv_cnnp_model_io_t), output_size, 0); | |||
| 517 | int i, j, k; | |||
| 518 | // Go through output one by one, reverse traversal them, to detect potential overlap (overlap means, for example, | |||
| 519 | // outputs[1] is an incoming node for outputs[0]. Thus, if we reverse them, we may have outputs[0] build before outputs[1], | |||
| 520 | // hence, having issues. | |||
| 521 | for (i = 0; i < output_size; i++) | |||
| 522 | outputs[i]->visit = 2; | |||
| 523 | for (i = output_size - 1; i >= 0; i--) | |||
| 524 | { | |||
| 525 | if (outputs[i]->visit == 3) // If we need to remove it, no need to visit. | |||
| 526 | continue; | |||
| 527 | 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", 527, __extension__ __PRETTY_FUNCTION__ ); })); | |||
| 528 | ccv_array_clear(reverse_top); | |||
| 529 | ccv_array_push(reverse_top, &outputs[i]); | |||
| 530 | for (j = 0; j < reverse_top->rnum; j++) | |||
| 531 | { | |||
| 532 | 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))); | |||
| 533 | 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", 533, __extension__ __PRETTY_FUNCTION__ ); })); | |||
| 534 | // If it is input, push it here. | |||
| 535 | if (output->incomings && !CCV_CNNP_IS_MODEL_PARAMETER(output)((output)->param_ref != 0 || (output)->param_sel != 0)) | |||
| 536 | for (k = 0; k < output->incomings->rnum; k++) | |||
| 537 | { | |||
| 538 | 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))); | |||
| 539 | // If it is an input or parameter, skip. | |||
| 540 | 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)) | |||
| 541 | continue; | |||
| 542 | if (input->visit == 1 || input->visit == 3) // Visited, skip. | |||
| 543 | continue; | |||
| 544 | // If this is an output, we need to remove it from the output array. Otherwise mark it as visited. | |||
| 545 | input->visit = input->visit == 2 ? 3 : 1; | |||
| 546 | ccv_array_push(reverse_top, &input); | |||
| 547 | } | |||
| 548 | // Similar for dependencies. | |||
| 549 | if (output->dependencies && !CCV_CNNP_IS_MODEL_PARAMETER(output)((output)->param_ref != 0 || (output)->param_sel != 0)) | |||
| 550 | for (k = 0; k < output->dependencies->rnum; k++) | |||
| 551 | { | |||
| 552 | 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))); | |||
| 553 | // If it is an input or parameter, skip. | |||
| 554 | 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)) | |||
| 555 | continue; | |||
| 556 | if (dependency->visit == 1 || dependency->visit == 3) // Visited, skip. | |||
| 557 | continue; | |||
| 558 | // If this is an output, we need to remove it from the output array. Otherwise mark it as visited. | |||
| 559 | dependency->visit = dependency->visit == 2 ? 3 : 1; | |||
| 560 | ccv_array_push(reverse_top, &dependency); | |||
| 561 | } | |||
| 562 | } | |||
| 563 | for (j = 1; j < reverse_top->rnum; j++) | |||
| 564 | { | |||
| 565 | 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))); | |||
| 566 | if (output->visit == 1) // Clean the visit back. | |||
| 567 | output->visit = 0; | |||
| 568 | } | |||
| 569 | } | |||
| 570 | ccv_array_clear(reverse_top); | |||
| 571 | for (i = 0; i < output_size; i++) // We will assign sequence in reverse order, thus, reverse the reverse top when copying the outputs. | |||
| 572 | { | |||
| 573 | if (outputs[output_size - 1 - i]->visit == 2) | |||
| 574 | ccv_array_push(reverse_top, &outputs[output_size - 1 - i]); | |||
| 575 | 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", 575, __extension__ __PRETTY_FUNCTION__ ); })); | |||
| 576 | outputs[output_size - 1 - i]->visit = 0; // Clean up all visits. | |||
| 577 | } | |||
| 578 | // Go from the output, until we meet inputs. | |||
| 579 | uint64_t input_bitmask[((input_size - 1) >> 6) + 1]; | |||
| 580 | memset(input_bitmask, 0, sizeof(uint64_t) * (((input_size - 1) >> 6) + 1)); | |||
| 581 | int tensor_output_size = 0; // io can be mapped to multiple tensor outputs, therefore, need to compute the exact tensor output size. | |||
| 582 | for (i = 0; i < output_size; i++) | |||
| 583 | tensor_output_size += outputs[i]->model->output_size; | |||
| 584 | for (i = 0; i < reverse_top->rnum; i++) | |||
| 585 | { | |||
| 586 | 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))); | |||
| 587 | 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", 587, __extension__ __PRETTY_FUNCTION__ ); })); | |||
| 588 | // If it is input, push it here. | |||
| 589 | if (output->incomings && !CCV_CNNP_IS_MODEL_PARAMETER(output)((output)->param_ref != 0 || (output)->param_sel != 0)) | |||
| 590 | for (j = 0; j < output->incomings->rnum; j++) | |||
| 591 | { | |||
| 592 | 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))); | |||
| 593 | ++input->visit; // Mark it as visited. | |||
| 594 | if (input->visit != input->outgoings->rnum + input->dependents) // Not all dependencies visited. | |||
| 595 | continue; | |||
| 596 | 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)) | |||
| 597 | ccv_array_push(reverse_top, &input); | |||
| 598 | else if (CCV_CNNP_IS_MODEL_INPUT(input->model)((input->model)->isa == &ccv_cnnp_input_isa)) { | |||
| 599 | for (k = 0; k < input_size; k++) | |||
| 600 | if (input == inputs[k]) | |||
| 601 | break; | |||
| 602 | 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", 602, __extension__ __PRETTY_FUNCTION__ ); })); | |||
| 603 | input_bitmask[k >> 6] |= ((uint64_t)1 << (k & 63)); | |||
| 604 | } | |||
| 605 | } | |||
| 606 | if (output->dependencies && !CCV_CNNP_IS_MODEL_PARAMETER(output)((output)->param_ref != 0 || (output)->param_sel != 0)) | |||
| 607 | for (j = 0; j < output->dependencies->rnum; j++) | |||
| 608 | { | |||
| 609 | 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))); | |||
| 610 | ++dependency->visit; // Mark it as visited. | |||
| 611 | if (dependency->visit != (dependency->outgoings ? dependency->outgoings->rnum : 0) + dependency->dependents) // Not all dependencies visited. | |||
| 612 | continue; | |||
| 613 | 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)) | |||
| 614 | ccv_array_push(reverse_top, &dependency); | |||
| 615 | else if (CCV_CNNP_IS_MODEL_INPUT(dependency->model)((dependency->model)->isa == &ccv_cnnp_input_isa)) { | |||
| 616 | for (k = 0; k < input_size; k++) | |||
| 617 | if (dependency == inputs[k]) | |||
| 618 | break; | |||
| 619 | 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", 619, __extension__ __PRETTY_FUNCTION__ ); })); | |||
| 620 | input_bitmask[k >> 6] |= ((uint64_t)1 << (k & 63)); | |||
| 621 | } | |||
| 622 | } | |||
| 623 | } | |||
| 624 | for (i = 0; i < reverse_top->rnum; i++) | |||
| 625 | { | |||
| 626 | 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))); | |||
| 627 | output->visit = 0; // Clean the visit back. | |||
| 628 | } | |||
| 629 | for (i = 0; i < input_size; i++) | |||
| 630 | inputs[i]->visit = 0; // Clean the visit back. | |||
| 631 | for (i = 0; i < input_size; i++) | |||
| 632 | { 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", 632, __extension__ __PRETTY_FUNCTION__ ); })); } // Assuming they all match. | |||
| 633 | const int sequence_size = reverse_top->rnum + input_size; | |||
| 634 | 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); | |||
| 635 | functional_model->super.isa = &ccv_cnnp_functional_model_isa; | |||
| 636 | functional_model->super.outputs = (ccv_nnc_tensor_symbol_t*)(functional_model->sequence + sequence_size); | |||
| 637 | functional_model->super.output_size = tensor_output_size; | |||
| 638 | functional_model->super.input_size = input_size; | |||
| 639 | functional_model->super.is_trainable = is_trainable; | |||
| 640 | functional_model->model_output_size = output_size; | |||
| 641 | functional_model->model_outputs = (int*)(functional_model->super.outputs + tensor_output_size); | |||
| 642 | ccv_cnnp_model_copy_name(&functional_model->super, name); | |||
| 643 | functional_model->sequence_size = sequence_size; | |||
| 644 | memcpy(functional_model->sequence, inputs, sizeof(ccv_cnnp_model_io_t) * input_size); | |||
| 645 | for (i = 0; i < reverse_top->rnum; i++) | |||
| 646 | 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))); | |||
| 647 | for (i = 0; i < output_size; i++) | |||
| 648 | { | |||
| 649 | for (j = sequence_size - 1; j >= input_size; j--) | |||
| 650 | if (functional_model->sequence[j] == outputs[i]) | |||
| 651 | { | |||
| 652 | functional_model->model_outputs[i] = j; | |||
| 653 | break; | |||
| 654 | } | |||
| 655 | } | |||
| 656 | ccv_array_free(reverse_top); | |||
| 657 | return (ccv_cnnp_model_t*)functional_model; | |||
| 658 | } | |||
| 659 | ||||
| 660 | static ccv_cnnp_model_t* _ccv_cnnp_input_copy(const ccv_cnnp_model_t* const self, void* const context) | |||
| 661 | { | |||
| 662 | ccv_cnnp_model_t* const input = (ccv_cnnp_model_t*)cccalloccalloc(1, sizeof(ccv_cnnp_model_t) + sizeof(ccv_nnc_tensor_symbol_t)); | |||
| 663 | input->isa = &ccv_cnnp_input_isa; | |||
| 664 | input->outputs = (ccv_nnc_tensor_symbol_t*)(input + 1); | |||
| 665 | input->output_size = 1; | |||
| 666 | return input; | |||
| 667 | } | |||
| 668 | ||||
| 669 | static const ccv_cnnp_model_vtab_t ccv_cnnp_input_isa = { | |||
| 670 | .copy = _ccv_cnnp_input_copy, | |||
| 671 | }; | |||
| 672 | ||||
| 673 | ccv_cnnp_model_io_t ccv_cnnp_input(void) | |||
| 674 | { | |||
| 675 | ccv_cnnp_model_t* const input = (ccv_cnnp_model_t*)cccalloccalloc(1, sizeof(ccv_cnnp_model_t) + sizeof(ccv_nnc_tensor_symbol_t)); | |||
| 676 | input->isa = &ccv_cnnp_input_isa; | |||
| 677 | input->io = ccv_array_new(sizeof(ccv_cnnp_model_io_t), 1, 0); | |||
| 678 | ccv_cnnp_model_io_t input_io = ccmallocmalloc(sizeof(struct ccv_cnnp_model_io_s) + sizeof(ccv_nnc_tensor_symbol_t)); | |||
| 679 | input_io->param_ref = 0; | |||
| 680 | input_io->param_sel = 0; | |||
| 681 | input_io->visit = 0; | |||
| 682 | input_io->incomings = 0; | |||
| 683 | input_io->dependencies = 0; | |||
| 684 | input_io->dependents = 0; | |||
| 685 | input_io->outgoings = 0; | |||
| 686 | input_io->model = input; | |||
| 687 | input_io->outputs = (ccv_nnc_tensor_symbol_t*)(input_io + 1); | |||
| 688 | ccv_array_push(input->io, &input_io); | |||
| 689 | input->outputs = (ccv_nnc_tensor_symbol_t*)(input + 1); | |||
| 690 | input->output_size = 1; | |||
| 691 | return input_io; | |||
| 692 | } | |||
| 693 | ||||
| 694 | // MARK - Dynamic Layer | |||
| 695 | ||||
| 696 | typedef struct { | |||
| 697 | ccv_cnnp_model_t super; | |||
| 698 | ccv_cnnp_model_dynamic_f func; | |||
| 699 | void* context; | |||
| 700 | ccv_cnnp_model_t* model; | |||
| 701 | } ccv_cnnp_dynamic_model_t; | |||
| 702 | ||||
| 703 | static void _ccv_cnnp_dynamic_model_deinit(ccv_cnnp_model_t* const super) | |||
| 704 | { | |||
| 705 | ccv_cnnp_dynamic_model_t* const self = (ccv_cnnp_dynamic_model_t*)super; | |||
| 706 | if (self->model) | |||
| 707 | ccv_cnnp_model_deinit(self->model); | |||
| 708 | } | |||
| 709 | ||||
| 710 | static void _ccv_cnnp_dynamic_model_dealloc(ccv_cnnp_model_t* const super) | |||
| 711 | { | |||
| 712 | ccv_cnnp_dynamic_model_t* const self = (ccv_cnnp_dynamic_model_t*)super; | |||
| 713 | if (self->model) | |||
| 714 | ccv_cnnp_model_free(self->model); | |||
| 715 | } | |||
| 716 | ||||
| 717 | static 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) | |||
| 718 | { | |||
| 719 | ccv_cnnp_dynamic_model_t* const self = (ccv_cnnp_dynamic_model_t*)super; | |||
| 720 | 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); | |||
| 721 | if (!self->model) | |||
| 722 | { | |||
| 723 | ccv_nnc_tensor_param_t input_params[input_size]; | |||
| 724 | int i; | |||
| 725 | for (i = 0; i < input_size; i++) | |||
| 726 | input_params[i] = ccv_nnc_tensor_symbol_params(graph, inputs[i]); | |||
| 727 | self->model = self->func(input_params, input_size, self->context); | |||
| 728 | // Update to use the settings of the compiled model. | |||
| 729 | self->super.input_size = self->model->input_size; | |||
| 730 | self->super.outputs = self->model->outputs; | |||
| 731 | self->super.output_size = self->model->output_size; | |||
| 732 | } | |||
| 733 | self->model->data = self->super.data; | |||
| 734 | ccv_cnnp_model_build(self->model, graph, inputs, input_size, outputs, output_size); | |||
| 735 | self->model->data = 0; | |||
| 736 | 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); | |||
| 737 | } | |||
| 738 | ||||
| 739 | static 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) | |||
| 740 | { | |||
| 741 | ccv_cnnp_dynamic_model_t* const self = (ccv_cnnp_dynamic_model_t*)super; | |||
| 742 | assert(self->model)((void) sizeof ((self->model) ? 1 : 0), __extension__ ({ if (self->model) ; else __assert_fail ("self->model", "ccv_cnnp_model_core.c" , 742, __extension__ __PRETTY_FUNCTION__); })); | |||
| 743 | ccv_cnnp_model_init_states(self->model, graph, initializer, context); | |||
| 744 | } | |||
| 745 | ||||
| 746 | static 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) | |||
| 747 | { | |||
| 748 | ccv_cnnp_dynamic_model_t* const self = (ccv_cnnp_dynamic_model_t*)super; | |||
| 749 | assert(self->model)((void) sizeof ((self->model) ? 1 : 0), __extension__ ({ if (self->model) ; else __assert_fail ("self->model", "ccv_cnnp_model_core.c" , 749, __extension__ __PRETTY_FUNCTION__); })); | |||
| 750 | ccv_cnnp_model_set_is_test(self->model, is_test, updater, context); | |||
| 751 | } | |||
| 752 | ||||
| 753 | static ccv_cnnp_model_t* _ccv_cnnp_dynamic_model_copy(const ccv_cnnp_model_t* const super, void* const context); | |||
| 754 | ||||
| 755 | static void _ccv_cnnp_dynamic_model_add_to_parameter_indices(ccv_cnnp_model_t* const super, const int index, ccv_array_t* const parameter_indices) | |||
| 756 | { | |||
| 757 | ccv_cnnp_dynamic_model_t* const self = (ccv_cnnp_dynamic_model_t*)super; | |||
| 758 | assert(self->model)((void) sizeof ((self->model) ? 1 : 0), __extension__ ({ if (self->model) ; else __assert_fail ("self->model", "ccv_cnnp_model_core.c" , 758, __extension__ __PRETTY_FUNCTION__); })); | |||
| 759 | ccv_cnnp_model_add_to_parameter_indices(self->model, index, parameter_indices); | |||
| 760 | } | |||
| 761 | ||||
| 762 | static void _ccv_cnnp_dynamic_model_notify(const ccv_cnnp_model_t* const super, const int tag, void* const payload) | |||
| 763 | { | |||
| 764 | ccv_cnnp_dynamic_model_t* const self = (ccv_cnnp_dynamic_model_t*)super; | |||
| 765 | if (self->model) | |||
| 766 | ccv_cnnp_model_notify(self->model, tag, payload); | |||
| 767 | } | |||
| 768 | ||||
| 769 | static const ccv_cnnp_model_vtab_t ccv_cnnp_dynamic_model_isa = { | |||
| 770 | .deinit = _ccv_cnnp_dynamic_model_deinit, | |||
| 771 | .dealloc = _ccv_cnnp_dynamic_model_dealloc, | |||
| 772 | .build = _ccv_cnnp_dynamic_model_build, | |||
| 773 | .init_states = _ccv_cnnp_dynamic_model_init_states, | |||
| 774 | .copy = _ccv_cnnp_dynamic_model_copy, | |||
| 775 | .set_is_test = _ccv_cnnp_dynamic_model_set_is_test, | |||
| 776 | .add_to_parameter_indices = _ccv_cnnp_dynamic_model_add_to_parameter_indices, | |||
| 777 | .notify = _ccv_cnnp_dynamic_model_notify, | |||
| 778 | }; | |||
| 779 | ||||
| 780 | ccv_cnnp_model_t* ccv_cnnp_dynamic_new(ccv_cnnp_model_dynamic_f func, void* const context, const char* const name) | |||
| 781 | { | |||
| 782 | ccv_cnnp_dynamic_model_t* const dynamic_model = (ccv_cnnp_dynamic_model_t*)cccalloccalloc(1, sizeof(ccv_cnnp_dynamic_model_t)); | |||
| 783 | dynamic_model->super.isa = &ccv_cnnp_dynamic_model_isa; | |||
| 784 | dynamic_model->super.is_trainable = -1; | |||
| 785 | dynamic_model->func = func; | |||
| 786 | dynamic_model->context = context; | |||
| 787 | ccv_cnnp_model_copy_name(&dynamic_model->super, name); | |||
| 788 | return (ccv_cnnp_model_t*)dynamic_model; | |||
| 789 | } | |||
| 790 | ||||
| 791 | static ccv_cnnp_model_t* _ccv_cnnp_dynamic_model_copy(const ccv_cnnp_model_t* const super, void* const context) | |||
| 792 | { | |||
| 793 | const ccv_cnnp_dynamic_model_t* const self = (const ccv_cnnp_dynamic_model_t*)super; | |||
| 794 | return ccv_cnnp_dynamic_new(self->func, self->context, self->super.name); | |||
| 795 | } | |||
| 796 | ||||
| 797 | // MARK - Command Layer | |||
| 798 | ||||
| 799 | typedef struct { | |||
| 800 | ccv_cnnp_model_t super; | |||
| 801 | ccv_nnc_cmd_t cmd; | |||
| 802 | ccv_nnc_hint_t hint; | |||
| 803 | ccv_nnc_tensor_symbol_t* input_symbols; // This is only valid for INIT_SHARED_TENSOR / INIT_SHARED_TENSOR_AS_TRAINABLE | |||
| 804 | ccv_nnc_tensor_symbol_t* output_symbols; // This is just for the output symbol (in case we need to have no tensor symbol). | |||
| 805 | ccv_cnnp_cmd_exec_io_t* inputs; | |||
| 806 | int flags; | |||
| 807 | int input_size; | |||
| 808 | int* outputs; | |||
| 809 | int output_size; | |||
| 810 | } ccv_cnnp_model_cmd_exec_t; | |||
| 811 | ||||
| 812 | static 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) | |||
| 813 | { | |||
| 814 | ccv_cnnp_model_cmd_exec_t* const self = (ccv_cnnp_model_cmd_exec_t*)super; | |||
| 815 | 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); | |||
| 816 | 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; })]; | |||
| 817 | int i, j; | |||
| 818 | for (i = 0, j = 0; i < self->input_size; i++) | |||
| 819 | if (self->inputs[i].type == CCV_CNNP_IO) | |||
| 820 | { | |||
| 821 | self->input_symbols[i] = inputs[j++]; | |||
| 822 | input_params[i] = ccv_nnc_tensor_symbol_params(graph, self->input_symbols[i]); | |||
| 823 | } else if (self->inputs[i].type == CCV_CNNP_NO_TENSOR) { | |||
| 824 | self->input_symbols[i] = NO_TENSOR_SYMBOL(const ccv_nnc_tensor_symbol_t){.d = CCV_NNC_NO_TENSOR_SYMBOL }; | |||
| 825 | } else if (!self->input_symbols[i].graph) { | |||
| 826 | // Otherwise, we only create this symbol if it doesn't exist. | |||
| 827 | const ccv_nnc_tensor_param_t params = self->inputs[i].init_state.info; | |||
| 828 | input_params[i] = params; | |||
| 829 | self->input_symbols[i] = ccv_nnc_tensor_symbol_new(graph, params, 0); | |||
| 830 | } | |||
| 831 | // We cannot simply mark the outputs as auto, because the subsequent build call may require this output to have params setup. | |||
| 832 | // Infer the parameters here. | |||
| 833 | 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; })]; | |||
| 834 | ccv_nnc_hint_tensor_auto(self->cmd, input_params, self->input_size, self->hint, output_params, self->output_size); | |||
| 835 | for (i = 0, j = 0; i < self->output_size; i++) | |||
| 836 | if (self->outputs[i] == CCV_CNNP_IO) | |||
| 837 | self->output_symbols[i] = outputs[j++] = ccv_nnc_tensor_symbol_new(graph, output_params[i], 0); | |||
| 838 | else if (self->outputs[i] == CCV_CNNP_TENSOR_NOT_OUTPUT) | |||
| 839 | self->output_symbols[i] = ccv_nnc_tensor_symbol_new(graph, output_params[i], 0); | |||
| 840 | else | |||
| 841 | self->output_symbols[i] = NO_TENSOR_SYMBOL(const ccv_nnc_tensor_symbol_t){.d = CCV_NNC_NO_TENSOR_SYMBOL }; | |||
| 842 | ccv_nnc_graph_exec_symbol_new(graph, self->cmd, self->input_symbols, self->input_size, self->output_symbols, self->output_size, 0); | |||
| 843 | } | |||
| 844 | ||||
| 845 | static 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) | |||
| 846 | { | |||
| 847 | ccv_cnnp_model_cmd_exec_t* const self = (ccv_cnnp_model_cmd_exec_t*)super; | |||
| 848 | int i; | |||
| 849 | for (i = 0; i < self->input_size; i++) | |||
| 850 | if (self->inputs[i].type == CCV_CNNP_INIT_SHARED_TENSOR || self->inputs[i].type == CCV_CNNP_INIT_SHARED_TENSOR_AS_TRAINABLE) | |||
| 851 | self->inputs[i].init_state.init(self->input_symbols[i], initializer, context, self->inputs[i].init_state.context); | |||
| 852 | } | |||
| 853 | ||||
| 854 | static 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) | |||
| 855 | { | |||
| 856 | ccv_cnnp_model_cmd_exec_t* const self = (ccv_cnnp_model_cmd_exec_t*)super; | |||
| 857 | int i; | |||
| 858 | for (i = 0; i < self->input_size; i++) | |||
| 859 | if (self->inputs[i].type == CCV_CNNP_INIT_SHARED_TENSOR) | |||
| 860 | add_to_array(outputs, self->input_symbols[i], 0); // Push this as retainable because it need to be init. | |||
| 861 | } | |||
| 862 | ||||
| 863 | static 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) | |||
| 864 | { | |||
| 865 | ccv_cnnp_model_cmd_exec_t* const self = (ccv_cnnp_model_cmd_exec_t*)super; | |||
| 866 | int i; | |||
| 867 | for (i = 0; i < self->input_size; i++) | |||
| 868 | if (self->inputs[i].type == CCV_CNNP_INIT_SHARED_TENSOR_AS_TRAINABLE) | |||
| 869 | add_to_array(parameters, self->input_symbols[i], is_trainable); // Push this as parameter. | |||
| 870 | } | |||
| 871 | ||||
| 872 | static void _ccv_cnnp_cmd_exec_deinit(ccv_cnnp_model_t* const super) | |||
| 873 | { | |||
| 874 | ccv_cnnp_model_cmd_exec_t* const self = (ccv_cnnp_model_cmd_exec_t*)super; | |||
| 875 | int i, j; | |||
| 876 | for (i = 0; i < self->input_size; i++) | |||
| 877 | if ((self->inputs[i].type == CCV_CNNP_INIT_SHARED_TENSOR || self->inputs[i].type == CCV_CNNP_INIT_SHARED_TENSOR_AS_TRAINABLE) && | |||
| 878 | self->inputs[i].init_state.context) | |||
| 879 | { | |||
| 880 | void* const context = self->inputs[i].init_state.context; | |||
| 881 | if (self->inputs[i].init_state.deinit) | |||
| 882 | self->inputs[i].init_state.deinit(context); | |||
| 883 | self->inputs[i].init_state.init = 0; | |||
| 884 | self->inputs[i].init_state.deinit = 0; | |||
| 885 | self->inputs[i].init_state.context = 0; | |||
| 886 | for (j = i + 1; j < self->input_size; j++) | |||
| 887 | if (self->inputs[j].init_state.context == context) | |||
| 888 | { | |||
| 889 | self->inputs[j].init_state.init = 0; | |||
| 890 | self->inputs[j].init_state.deinit = 0; | |||
| 891 | self->inputs[j].init_state.context = 0; | |||
| 892 | } | |||
| 893 | } | |||
| 894 | } | |||
| 895 | ||||
| 896 | static ccv_cnnp_model_t* _ccv_cnnp_cmd_exec_copy(const ccv_cnnp_model_t* const super, void* const context); | |||
| 897 | ||||
| 898 | static const ccv_cnnp_model_vtab_t ccv_cnnp_cmd_exec_isa = { | |||
| 899 | .build = _ccv_cnnp_cmd_exec_build, | |||
| 900 | .init_states = _ccv_cnnp_cmd_exec_init_states, | |||
| 901 | .add_to_parameter = _ccv_cnnp_cmd_exec_add_to_parameter, | |||
| 902 | .add_to_output = _ccv_cnnp_cmd_exec_add_to_output, | |||
| 903 | .deinit = _ccv_cnnp_cmd_exec_deinit, | |||
| 904 | .copy = _ccv_cnnp_cmd_exec_copy, | |||
| 905 | }; | |||
| 906 | ||||
| 907 | static 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) | |||
| 908 | { | |||
| 909 | 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", 909, __extension__ __PRETTY_FUNCTION__ ); })); | |||
| 910 | 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", 910, __extension__ __PRETTY_FUNCTION__ ); })); | |||
| 911 | int i; | |||
| 912 | int io_input_size = 0; | |||
| 913 | for (i = 0; i < input_size; i++) | |||
| 914 | if (inputs[i].type == CCV_CNNP_IO) | |||
| 915 | ++io_input_size; | |||
| 916 | else { | |||
| 917 | 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", 917, __extension__ __PRETTY_FUNCTION__ ); })); | |||
| 918 | 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", 918, __extension__ __PRETTY_FUNCTION__ ); })); | |||
| 919 | } | |||
| 920 | int io_output_size = 0; | |||
| 921 | for (i = 0; i < output_size; i++) | |||
| 922 | if (outputs[i] == CCV_CNNP_IO) | |||
| 923 | ++io_output_size; | |||
| 924 | else { | |||
| 925 | 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", 925, __extension__ __PRETTY_FUNCTION__ ); })); | |||
| 926 | } | |||
| 927 | 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", 927, __extension__ __PRETTY_FUNCTION__ ); })); | |||
| 928 | 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); | |||
| 929 | model_cmd_exec->super.isa = &ccv_cnnp_cmd_exec_isa; | |||
| 930 | model_cmd_exec->super.input_size = io_input_size; | |||
| 931 | model_cmd_exec->super.outputs = (ccv_nnc_tensor_symbol_t*)(model_cmd_exec + 1); | |||
| 932 | model_cmd_exec->super.output_size = io_output_size; | |||
| 933 | model_cmd_exec->super.is_trainable = is_trainable; | |||
| 934 | ccv_cnnp_model_copy_name(&model_cmd_exec->super, name); | |||
| 935 | model_cmd_exec->cmd = cmd; | |||
| 936 | model_cmd_exec->hint = hint; | |||
| 937 | model_cmd_exec->flags = flags; | |||
| 938 | model_cmd_exec->input_size = input_size; | |||
| 939 | model_cmd_exec->input_symbols = model_cmd_exec->super.outputs + io_output_size; | |||
| 940 | model_cmd_exec->output_symbols = model_cmd_exec->input_symbols + input_size; | |||
| 941 | model_cmd_exec->inputs = (ccv_cnnp_cmd_exec_io_t*)(model_cmd_exec->output_symbols + output_size); | |||
| 942 | if (input_size > 0) | |||
| 943 | { | |||
| 944 | memcpy(model_cmd_exec->inputs, inputs, sizeof(ccv_cnnp_cmd_exec_io_t) * input_size); | |||
| 945 | if (copy_io) | |||
| 946 | for (i = 0; i < input_size; i++) | |||
| 947 | if (inputs[i].type != CCV_CNNP_IO && inputs[i].init_state.copy) | |||
| 948 | model_cmd_exec->inputs[i].init_state.context = inputs[i].init_state.copy(inputs[i].init_state.context); | |||
| 949 | } | |||
| 950 | model_cmd_exec->output_size = output_size; | |||
| 951 | model_cmd_exec->outputs = (int*)(model_cmd_exec->inputs + input_size); | |||
| 952 | if (output_size > 0) | |||
| 953 | memcpy(model_cmd_exec->outputs, outputs, sizeof(int) * output_size); | |||
| 954 | return (ccv_cnnp_model_t*)model_cmd_exec; | |||
| 955 | } | |||
| 956 | ||||
| 957 | ccv_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) | |||
| 958 | { | |||
| 959 | return _ccv_cnnp_cmd_exec(cmd, 0, hint, flags, inputs, input_size, outputs, output_size, is_trainable, name); | |||
| 960 | } | |||
| 961 | ||||
| 962 | static ccv_cnnp_model_t* _ccv_cnnp_cmd_exec_copy(const ccv_cnnp_model_t* const super, void* const context) | |||
| 963 | { | |||
| 964 | const ccv_cnnp_model_cmd_exec_t* const self = (const ccv_cnnp_model_cmd_exec_t*)super; | |||
| 965 | 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); | |||
| 966 | } | |||
| 967 | ||||
| 968 | static 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) | |||
| 969 | { | |||
| 970 | 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); | |||
| 971 | } | |||
| 972 | ||||
| 973 | ccv_cnnp_cmd_exec_io_init_state_t ccv_cnnp_cmd_exec_io_copy(const ccv_nnc_tensor_t* const tensor) | |||
| 974 | { | |||
| 975 | return (ccv_cnnp_cmd_exec_io_init_state_t){ | |||
| 976 | .info = tensor->info, | |||
| 977 | .context = (void *)tensor, | |||
| 978 | .init = _ccv_cnnp_cmd_exec_io_copy, | |||
| 979 | }; | |||
| 980 | } | |||
| 981 | ||||
| 982 | typedef struct { | |||
| 983 | ccv_nnc_cmd_t cmd; | |||
| 984 | ccv_nnc_hint_t hint; | |||
| 985 | int flags; | |||
| 986 | } ccv_cnnp_cmd_exec_io_set_by_t; | |||
| 987 | ||||
| 988 | static 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) | |||
| 989 | { | |||
| 990 | const ccv_cnnp_cmd_exec_io_set_by_t* const set_by = (ccv_cnnp_cmd_exec_io_set_by_t*)context; | |||
| 991 | initializer(initializer_context, set_by->cmd, set_by->hint, set_by->flags, 0, tensor_symbol); | |||
| 992 | } | |||
| 993 | ||||
| 994 | static void* _ccv_cnnp_cmd_exec_io_set_by_copy(void* const context) | |||
| 995 | { | |||
| 996 | 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)); | |||
| 997 | memcpy(set_by, context, sizeof(ccv_cnnp_cmd_exec_io_set_by_t)); | |||
| 998 | return set_by; | |||
| 999 | } | |||
| 1000 | ||||
| 1001 | ccv_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) | |||
| 1002 | { | |||
| 1003 | 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)); | |||
| 1004 | set_by->cmd = cmd; | |||
| 1005 | set_by->hint = hint; | |||
| 1006 | set_by->flags = flags; | |||
| 1007 | return (ccv_cnnp_cmd_exec_io_init_state_t){ | |||
| 1008 | .info = params, | |||
| 1009 | .context = set_by, | |||
| 1010 | .init = _ccv_cnnp_cmd_exec_io_set_by, | |||
| 1011 | .copy = _ccv_cnnp_cmd_exec_io_set_by_copy, | |||
| 1012 | .deinit = ccfreefree, | |||
| 1013 | }; | |||
| 1014 | } |