/home/liu/actions-runner/_work/ccv/ccv/lib/nnc/ccv_cnnp_model_io.c
Line | Count | Source (jump to first uncovered line) |
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/sqlite3/sqlite3.h" |
7 | | #ifdef HAVE_CUDA |
8 | | #include "gpu/ccv_nnc_compat.h" |
9 | | #endif |
10 | | |
11 | | #ifdef NDEBUG |
12 | | #define SQLITE_ENFORCE(stmt) (void)(stmt) |
13 | | #else |
14 | 2 | #define SQLITE_ENFORCE assert |
15 | | #endif |
16 | | |
17 | | static inline int _model_tensor_write(const ccv_cnnp_model_t* const self, const ccv_nnc_tensor_t* const tensor, const char* const sql, void* const handle, const char* const name, const ccv_nnc_tensor_io_option_t* const options) |
18 | 12 | { |
19 | 12 | if (self->rw.writer) |
20 | 0 | return self->rw.writer(tensor, sql, handle, name, options); |
21 | 12 | if (sql) |
22 | 2 | { |
23 | 2 | sqlite3* conn = (sqlite3*)handle; |
24 | 2 | SQLITE_ENFORCE(SQLITE_OK == sqlite3_exec(conn, sql, 0, 0, 0)); |
25 | 2 | return CCV_IO_FINAL; |
26 | 2 | } else |
27 | 10 | return ccv_nnc_tensor_write(tensor, handle, name, options); |
28 | 12 | } |
29 | | |
30 | | int ccv_cnnp_model_write(const ccv_cnnp_model_t* const model, void* const handle, const char* const name, const ccv_nnc_tensor_io_option_t* const options) |
31 | 1 | { |
32 | 1 | ccv_cnnp_compiled_data_t* const compiled_data = model->compiled_data; |
33 | 1 | assert(compiled_data); // The model has to be compiled. |
34 | 1 | _model_tensor_write(model, 0, "BEGIN", handle, 0, options); |
35 | 1 | int i, j; |
36 | 1 | const int parallel_count = ccv_max(model->parallel_count, 1); |
37 | 1 | const int parameter_size = compiled_data->parameters->rnum; |
38 | 1 | const int internal_size = compiled_data->internals->rnum; |
39 | 1 | char internal_name[2048 + 16]; |
40 | 11 | for (i = 0; i < parameter_size; i++10 ) |
41 | 10 | { |
42 | 10 | const char* const id = *(char**)ccv_array_get(compiled_data->ids.parameters, i); |
43 | 10 | if (name) |
44 | 0 | snprintf(internal_name, 2048 + 16, "__%s__[%s]", name, id); |
45 | 10 | else |
46 | 10 | snprintf(internal_name, 2048 + 16, "%s", id); |
47 | 10 | _model_tensor_write(model, CCV_NNC_TENSOR(compiled_data->tensors.parameters[i]), 0, handle, internal_name, options); |
48 | 10 | } |
49 | 2 | for (i = 0; i < parallel_count; i++1 ) |
50 | 1 | for (j = 0; j < internal_size; j++0 ) |
51 | 0 | { |
52 | 0 | const char* const id = *(char**)ccv_array_get(compiled_data->ids.internals, j); |
53 | 0 | if (name) |
54 | 0 | snprintf(internal_name, 2048 + 16, "__%s__[%s(%d)]", name, id, i); |
55 | 0 | else |
56 | 0 | snprintf(internal_name, 2048 + 16, "%s(%d)", id, i); |
57 | 0 | _model_tensor_write(model, compiled_data->tensors.internals[i * internal_size + j], 0, handle, internal_name, options); |
58 | 0 | } |
59 | 1 | _model_tensor_write(model, 0, "COMMIT", handle, 0, options); |
60 | 1 | return CCV_IO_FINAL; |
61 | 1 | } |
62 | | |
63 | | static inline int _model_tensor_read(const ccv_cnnp_model_t* const self, void* const handle, const char* const name, const ccv_nnc_tensor_io_option_t* const options, const ccv_nnc_tensor_param_t info, ccv_nnc_tensor_t** const tensor_out) |
64 | 10 | { |
65 | 10 | if (self->rw.reader) |
66 | 0 | return self->rw.reader(handle, name, options, info, tensor_out); |
67 | 10 | return ccv_nnc_tensor_read(handle, name, options, 0, &info, tensor_out); |
68 | 10 | } |
69 | | |
70 | | int ccv_cnnp_model_read(void* const handle, const char* const name, const ccv_nnc_tensor_io_option_t* const options, const ccv_cnnp_model_t* const model_out) |
71 | 1 | { |
72 | 1 | sqlite3* conn = (sqlite3*)handle; |
73 | 1 | assert(conn); |
74 | 1 | ccv_cnnp_compiled_data_t* const compiled_data = model_out->compiled_data; |
75 | 1 | assert(compiled_data); // The model has to be compiled. |
76 | 1 | const int tensors_init = !!compiled_data->tensors_init.v; |
77 | 1 | if (!tensors_init) |
78 | 1 | ccv_cnnp_model_tensors_init_0(model_out, compiled_data); |
79 | 1 | int i, j; |
80 | 1 | const int parallel_count = ccv_max(model_out->parallel_count, 1); |
81 | 1 | const int parameter_size = compiled_data->parameters->rnum; |
82 | 1 | const int internal_size = compiled_data->internals->rnum; |
83 | 1 | char internal_name[2048 + 16]; |
84 | 1 | uint32_t* const init_v = CCV_NNC_INIT_V(compiled_data->tensors_init.v); |
85 | 11 | for (i = 0; i < parameter_size; i++10 ) |
86 | 10 | { |
87 | 10 | const char* const id = *(char**)ccv_array_get(compiled_data->ids.parameters, i); |
88 | 10 | if (name) |
89 | 0 | snprintf(internal_name, 2048 + 16, "__%s__[%s]", name, id); |
90 | 10 | else |
91 | 10 | snprintf(internal_name, 2048 + 16, "%s", id); |
92 | 10 | const ccv_nnc_tensor_symbol_t parameter = *(ccv_nnc_tensor_symbol_t*)ccv_array_get(compiled_data->parameters, i); |
93 | 10 | const int d = parameter.d; |
94 | 10 | ccv_nnc_tensor_param_t info = ccv_nnc_tensor_symbol_params(parameter.graph, parameter); |
95 | 10 | if (CCV_TENSOR_GET_DEVICE(info.type) == CCV_COMPUTE_DEVICE_ANY) |
96 | 10 | CCV_TENSOR_SET_DEVICE_ID(info.type, 0); |
97 | 10 | const int device_id = CCV_TENSOR_GET_DEVICE_ID(info.type); |
98 | 10 | if (compiled_data->tensors.parameters[i]) // Cannot be a shared parameter to read. |
99 | 0 | { assert(!((uintptr_t)compiled_data->tensors.parameters[i] & (uintptr_t)1)); } |
100 | 10 | if (_model_tensor_read(model_out, conn, internal_name, options, info, compiled_data->tensors.parameters + i) == CCV_IO_FINAL) |
101 | 10 | { |
102 | 10 | init_v[d >> 5] |= (1u << (d & 0x1f)); |
103 | | // Create this tensor for other data parallel allocations. |
104 | 10 | info = compiled_data->tensors.parameters[i]->info; // In case we loaded a different info. |
105 | 10 | for (j = 1; j < parallel_count; j++0 ) |
106 | 0 | if (!compiled_data->tensors.parameters[i + j * parameter_size]) |
107 | 0 | { |
108 | 0 | if (j != device_id) |
109 | 0 | CCV_TENSOR_SET_DEVICE_ID(info.type, j); |
110 | 0 | else |
111 | 0 | CCV_TENSOR_SET_DEVICE_ID(info.type, 0); |
112 | 0 | compiled_data->tensors.parameters[i + j * parameter_size] = ccv_nnc_tensor_new(0, info, 0); |
113 | 0 | } |
114 | | // No need to copy over, this is done in ccv_cnnp_model.c's copy_tensors method. |
115 | 10 | } |
116 | 10 | } |
117 | 2 | for (i = 0; 1 i < parallel_count; i++1 ) |
118 | 1 | for (j = 0; j < internal_size; j++0 ) |
119 | 0 | { |
120 | 0 | const char* const id = *(char**)ccv_array_get(compiled_data->ids.internals, j); |
121 | 0 | if (name) |
122 | 0 | snprintf(internal_name, 2048 + 16, "__%s__[%s(%d)]", name, id, i); |
123 | 0 | else |
124 | 0 | snprintf(internal_name, 2048 + 16, "%s(%d)", id, i); |
125 | 0 | const ccv_nnc_tensor_symbol_t retained = *(ccv_nnc_tensor_symbol_t*)ccv_array_get(compiled_data->internals, j); |
126 | 0 | const int d = retained.d; |
127 | 0 | ccv_nnc_tensor_param_t info = ccv_nnc_tensor_symbol_params(retained.graph, retained); |
128 | 0 | if (CCV_TENSOR_GET_DEVICE(info.type) == CCV_COMPUTE_DEVICE_ANY) |
129 | 0 | CCV_TENSOR_SET_DEVICE_ID(info.type, 0); |
130 | 0 | if (i > 0) |
131 | 0 | { |
132 | 0 | const int device_id = CCV_TENSOR_GET_DEVICE_ID(info.type); |
133 | 0 | if (i != device_id) |
134 | 0 | CCV_TENSOR_SET_DEVICE_ID(info.type, i); |
135 | 0 | else |
136 | 0 | CCV_TENSOR_SET_DEVICE_ID(info.type, 0); |
137 | 0 | } |
138 | 0 | if (_model_tensor_read(model_out, conn, internal_name, options, info, compiled_data->tensors.internals + i * internal_size + j) == CCV_IO_FINAL) |
139 | 0 | init_v[d >> 5] |= (1u << (d & 0x1f)); |
140 | 0 | } |
141 | | // Mark it as to have some other tensors to allocate. |
142 | 1 | if (ccv_cnnp_model_tensors_any_to_alloc(model_out, compiled_data)) |
143 | 0 | compiled_data->tensors_init.v = (uint32_t*)((uintptr_t)compiled_data->tensors_init.v | (uintptr_t)1); |
144 | 1 | else // Remove the flag. |
145 | 1 | compiled_data->tensors_init.v = CCV_NNC_INIT_V(compiled_data->tensors_init.v); |
146 | 1 | return CCV_IO_FINAL; |
147 | 1 | } |
148 | | |
149 | | void ccv_cnnp_model_write_to_file(ccv_cnnp_model_t* const model, const char* const fn, const ccv_nnc_tensor_io_option_t* const options) |
150 | 1 | { |
151 | 1 | ccv_cnnp_compiled_data_t* const compiled_data = model->compiled_data; |
152 | 1 | assert(compiled_data); // The model has to be compiled. |
153 | 1 | sqlite3* conn = 0; |
154 | 1 | if (SQLITE_OK != sqlite3_open(fn, &conn)) |
155 | 0 | return; |
156 | 1 | ccv_cnnp_model_write(model, conn, 0, options); |
157 | 1 | sqlite3_close(conn); |
158 | 1 | } |
159 | | |
160 | | void ccv_cnnp_model_read_from_file(const char* const fn, const ccv_nnc_tensor_io_option_t* const options, const ccv_cnnp_model_t* const model) |
161 | 1 | { |
162 | 1 | ccv_cnnp_compiled_data_t* const compiled_data = model->compiled_data; |
163 | 1 | assert(compiled_data); // The model has to be compiled. |
164 | 1 | sqlite3* conn = 0; |
165 | 1 | if (SQLITE_OK != sqlite3_open(fn, &conn)) |
166 | 0 | return; |
167 | 1 | ccv_cnnp_model_read(conn, 0, options, model); |
168 | 1 | sqlite3_close(conn); |
169 | 1 | } |
170 | | |
171 | | void ccv_cnnp_model_set_io(ccv_cnnp_model_t* const model, ccv_cnnp_model_io_reader_f reader, ccv_cnnp_model_io_writer_f writer) |
172 | 0 | { |
173 | 0 | model->rw.reader = reader; |
174 | 0 | model->rw.writer = writer; |
175 | 0 | } |