Line data Source code
1 : /**
2 : * Copyright (C) 2020 Samsung Electronics Co., Ltd. All Rights Reserved.
3 : *
4 : * Licensed under the Apache License, Version 2.0 (the "License");
5 : * you may not use this file except in compliance with the License.
6 : * You may obtain a copy of the License at
7 : * http://www.apache.org/licenses/LICENSE-2.0
8 : * Unless required by applicable law or agreed to in writing, software
9 : * distributed under the License is distributed on an "AS IS" BASIS,
10 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 : * See the License for the specific language governing permissions and
12 : * limitations under the License.
13 : */
14 : /**
15 : * @file nntrainer.cpp
16 : * @date 02 April 2020
17 : * @brief NNTrainer C-API Wrapper.
18 : * This allows to construct and control NNTrainer Model.
19 : * @see https://github.com/nnstreamer/nntrainer
20 : * @author Jijoong Moon <jijoong.moon@samsung.com>
21 : * @author Parichay Kapoor <pk.kapoor@samsung.com>
22 : * @bug No known bugs except for NYI items
23 : */
24 :
25 : #include <array>
26 : #include <cstdarg>
27 : #include <cstring>
28 : #include <nntrainer.h>
29 : #include <nntrainer_internal.h>
30 : #include <sstream>
31 : #include <string>
32 :
33 : #include <nntrainer_error.h>
34 : #include <nntrainer_log.h>
35 :
36 : /**
37 : * @brief Global lock for nntrainer C-API
38 : * @details This lock ensures that ml_train_model_destroy is thread safe. All
39 : * other API functions use the mutex from their object handle. However
40 : * for destroy, object mutex cannot be used as their handles are
41 : * destroyed at destroy.
42 : */
43 : std::mutex GLOCK;
44 :
45 : /**
46 : * @brief Adopt the lock to the current scope for the object
47 : */
48 : #define ML_TRAIN_ADOPT_LOCK(obj, obj_lock) \
49 : std::lock_guard<std::mutex> obj_lock(obj->m, std::adopt_lock)
50 :
51 : /**
52 : * @brief function to wrap an exception to predefined error value
53 : * @param[in] func must be wrapped inside lambda []() -> int otherwise compile
54 : * error will be raised
55 : * @retval errorno
56 : */
57 535 : template <typename F> static int nntrainer_exception_boundary(F &&func) {
58 535 : int status = ML_ERROR_NONE;
59 :
60 : /**< Exception boundary for cpp exceptions */
61 : /// @note aware that some exception are inheritance of others so should be
62 : /// caught before than some
63 : try {
64 493 : status = func();
65 4 : } catch (nntrainer::exception::not_supported &e) {
66 2 : ml_loge("%s %s", typeid(e).name(), e.what());
67 : return ML_ERROR_INVALID_PARAMETER;
68 0 : } catch (nntrainer::exception::permission_denied &e) {
69 0 : ml_loge("%s %s", typeid(e).name(), e.what());
70 : return ML_ERROR_PERMISSION_DENIED;
71 70 : } catch (std::invalid_argument &e) {
72 35 : ml_loge("%s %s", typeid(e).name(), e.what());
73 : return ML_ERROR_INVALID_PARAMETER;
74 0 : } catch (std::range_error &e) {
75 0 : ml_loge("%s %s", typeid(e).name(), e.what());
76 : return ML_ERROR_INVALID_PARAMETER;
77 6 : } catch (std::out_of_range &e) {
78 3 : ml_loge("%s %s", typeid(e).name(), e.what());
79 : return ML_ERROR_INVALID_PARAMETER;
80 4 : } catch (std::logic_error &e) {
81 2 : ml_loge("%s %s", typeid(e).name(), e.what());
82 : return ML_ERROR_INVALID_PARAMETER;
83 0 : } catch (std::bad_alloc &e) {
84 0 : ml_loge("%s %s", typeid(e).name(), e.what());
85 : return ML_ERROR_OUT_OF_MEMORY;
86 0 : } catch (std::exception &e) {
87 0 : ml_loge("%s %s", typeid(e).name(), e.what());
88 : return ML_ERROR_UNKNOWN;
89 0 : } catch (...) {
90 0 : ml_loge("unknown error type thrown");
91 : return ML_ERROR_UNKNOWN;
92 : }
93 :
94 : /**< Exception boundary for specialized error code */
95 : /// @todo deprecate this with #233
96 493 : switch (status) {
97 : case ML_ERROR_BAD_ADDRESS:
98 : return ML_ERROR_OUT_OF_MEMORY;
99 0 : case ML_ERROR_RESULT_OUT_OF_RANGE:
100 0 : return ML_ERROR_INVALID_PARAMETER;
101 493 : default:
102 493 : return status;
103 : }
104 : }
105 :
106 : typedef std::function<int()> returnable;
107 :
108 : /**
109 : * @brief std::make_shared wrapped with exception boundary
110 : *
111 : * @tparam Tv value type.
112 : * @tparam Tp pointer type.
113 : * @tparam Types args used to construct
114 : * @param target pointer
115 : * @param args args
116 : * @return int error value. ML_ERROR_OUT_OF_MEMORY if fail
117 : */
118 : template <typename Tv, typename Tp, typename... Types>
119 : static int exception_bounded_make_shared(Tp &target, Types... args) {
120 : returnable f = [&]() {
121 : target = std::make_shared<Tv>(args...);
122 : return ML_ERROR_NONE;
123 : };
124 :
125 : return nntrainer_exception_boundary(f);
126 : }
127 :
128 : /**
129 : * @brief Create dataset with different types of train/test/valid data source
130 : * @param[in] dataset dataset object to be created
131 : * @param[in] type type of the dataset
132 : * @param[in] train training data source
133 : * @param[in] valid validation data source
134 : * @param[in] test testing data source
135 : */
136 : template <typename T>
137 34 : static int ml_train_dataset_create(ml_train_dataset_h *dataset,
138 : ml::train::DatasetType type, T train,
139 : T valid, T test) {
140 34 : int status = ML_ERROR_NONE;
141 :
142 34 : check_feature_state();
143 34 : if (dataset == NULL) {
144 : return ML_ERROR_INVALID_PARAMETER;
145 : }
146 :
147 33 : ml_train_dataset *nndataset = new ml_train_dataset;
148 33 : nndataset->magic = ML_NNTRAINER_MAGIC;
149 33 : nndataset->in_use = false;
150 :
151 107 : returnable f = [&]() {
152 19 : if (train != nullptr) {
153 30 : nndataset->dataset[ML_TRAIN_DATASET_MODE_TRAIN] =
154 : ml::train::createDataset(type, train);
155 : }
156 18 : if (valid != nullptr) {
157 6 : nndataset->dataset[ML_TRAIN_DATASET_MODE_VALID] =
158 : ml::train::createDataset(type, valid);
159 : }
160 18 : if (test != nullptr) {
161 5 : nndataset->dataset[ML_TRAIN_DATASET_MODE_TEST] =
162 : ml::train::createDataset(type, test);
163 : }
164 18 : return ML_ERROR_NONE;
165 : };
166 :
167 33 : status = nntrainer_exception_boundary(f);
168 33 : if (status != ML_ERROR_NONE) {
169 2 : delete nndataset;
170 1 : ml_loge("Error: Create dataset failed");
171 : } else {
172 32 : *dataset = nndataset;
173 : }
174 :
175 33 : return status;
176 : }
177 :
178 : /**
179 : * @brief add ml::train::Dataset to @a dataset
180 : *
181 : * @tparam Args args needed to create the dataset
182 : * @param dataset dataset handle
183 : * @param mode target mode
184 : * @param type dataset type
185 : * @param args args needed to create the dataset
186 : * @retval #ML_ERROR_NONE Successful
187 : * @retval #ML_ERROR_INVALID_PARAMETER if parameter is invalid
188 : */
189 : template <typename... Args>
190 17 : static int ml_train_dataset_add_(ml_train_dataset_h dataset,
191 : ml_train_dataset_mode_e mode,
192 : ml::train::DatasetType type, Args &&... args) {
193 17 : check_feature_state();
194 17 : std::shared_ptr<ml::train::Dataset> underlying_dataset;
195 :
196 50 : returnable f = [&]() {
197 57 : underlying_dataset =
198 17 : ml::train::createDataset(type, std::forward<Args>(args)...);
199 16 : return ML_ERROR_NONE;
200 : };
201 :
202 17 : int status = nntrainer_exception_boundary(f);
203 17 : if (status != ML_ERROR_NONE) {
204 1 : ml_loge("Failed to create dataset");
205 : return status;
206 : }
207 :
208 16 : if (underlying_dataset == nullptr) {
209 : return ML_ERROR_INVALID_PARAMETER;
210 : }
211 :
212 : ml_train_dataset *nndataset;
213 16 : ML_TRAIN_VERIFY_VALID_HANDLE(dataset);
214 :
215 : {
216 15 : ML_TRAIN_GET_VALID_DATASET_LOCKED(nndataset, dataset);
217 32 : ML_TRAIN_ADOPT_LOCK(nndataset, dataset_lock);
218 :
219 15 : nndataset->dataset[mode] = underlying_dataset;
220 : }
221 : return status;
222 : }
223 :
224 : #ifdef __cplusplus
225 : extern "C" {
226 : #endif
227 :
228 : /**
229 : * @brief Function to create ml::train::Model object.
230 : */
231 47 : static int nn_object(ml_train_model_h *model) {
232 47 : int status = ML_ERROR_NONE;
233 :
234 47 : if (model == NULL)
235 : return ML_ERROR_INVALID_PARAMETER;
236 :
237 46 : ml_train_model *nnmodel = new ml_train_model;
238 46 : nnmodel->magic = ML_NNTRAINER_MAGIC;
239 46 : nnmodel->optimizer = NULL;
240 46 : nnmodel->dataset = NULL;
241 :
242 46 : *model = nnmodel;
243 :
244 92 : returnable f = [&]() {
245 46 : nnmodel->model = ml::train::createModel(ml::train::ModelType::NEURAL_NET);
246 46 : return ML_ERROR_NONE;
247 93 : };
248 :
249 46 : status = nntrainer_exception_boundary(f);
250 46 : if (status != ML_ERROR_NONE) {
251 0 : delete nnmodel;
252 0 : ml_loge("Error: creating nn object failed");
253 : }
254 :
255 46 : return status;
256 : }
257 :
258 47 : int ml_train_model_construct(ml_train_model_h *model) {
259 47 : int status = ML_ERROR_NONE;
260 :
261 47 : check_feature_state();
262 :
263 141 : returnable f = [&]() { return nn_object(model); };
264 :
265 47 : status = nntrainer_exception_boundary(f);
266 47 : return status;
267 : }
268 :
269 26 : int ml_train_model_construct_with_conf(const char *model_conf,
270 : ml_train_model_h *model) {
271 26 : int status = ML_ERROR_NONE;
272 26 : ml_train_model *nnmodel;
273 26 : std::shared_ptr<ml::train::Model> m;
274 52 : returnable f;
275 :
276 26 : status = ml_train_model_construct(model);
277 26 : if (status != ML_ERROR_NONE)
278 : return status;
279 :
280 26 : nnmodel = (ml_train_model *)(*model);
281 26 : m = nnmodel->model;
282 :
283 78 : f = [&]() { return m->loadFromConfig(model_conf); };
284 26 : status = nntrainer_exception_boundary(f);
285 26 : if (status != ML_ERROR_NONE) {
286 2 : ml_train_model_destroy(*model);
287 : }
288 :
289 : return status;
290 : }
291 :
292 26 : int ml_train_model_compile(ml_train_model_h model, ...) {
293 26 : int status = ML_ERROR_NONE;
294 26 : const char *data;
295 26 : ml_train_model *nnmodel;
296 52 : returnable f;
297 26 : std::shared_ptr<ml::train::Model> m;
298 :
299 26 : check_feature_state();
300 :
301 26 : ML_TRAIN_VERIFY_VALID_HANDLE(model);
302 :
303 25 : std::vector<std::string> arg_list;
304 25 : va_list arguments;
305 25 : va_start(arguments, model);
306 :
307 36 : while ((data = va_arg(arguments, const char *))) {
308 22 : arg_list.push_back(data);
309 : }
310 25 : va_end(arguments);
311 :
312 25 : {
313 50 : ML_TRAIN_GET_VALID_MODEL_LOCKED(nnmodel, model);
314 25 : ML_TRAIN_ADOPT_LOCK(nnmodel, model_lock);
315 25 : m = nnmodel->model;
316 : }
317 :
318 50 : f = [&]() {
319 25 : m->setProperty(arg_list);
320 22 : return ML_ERROR_NONE;
321 25 : };
322 25 : status = nntrainer_exception_boundary(f);
323 25 : if (status != ML_ERROR_NONE)
324 : return status;
325 :
326 44 : f = [&]() { return m->compile(); };
327 22 : status = nntrainer_exception_boundary(f);
328 22 : if (status != ML_ERROR_NONE)
329 : return status;
330 :
331 44 : f = [&]() { return m->initialize(); };
332 25 : status = nntrainer_exception_boundary(f);
333 : if (status != ML_ERROR_NONE)
334 : return status;
335 :
336 : return status;
337 : }
338 :
339 4 : int ml_train_model_compile_with_single_param(ml_train_model_h model,
340 : const char *single_param) {
341 4 : ML_TRAIN_VERIFY_VALID_HANDLE(model);
342 :
343 4 : return ml_train_model_compile(model, single_param, NULL);
344 : }
345 :
346 11 : int ml_train_model_run(ml_train_model_h model, ...) {
347 11 : int status = ML_ERROR_NONE;
348 11 : ml_train_model *nnmodel;
349 11 : const char *data;
350 11 : std::shared_ptr<ml::train::Model> m;
351 :
352 11 : check_feature_state();
353 :
354 11 : ML_TRAIN_VERIFY_VALID_HANDLE(model);
355 :
356 10 : std::vector<std::string> arg_list;
357 10 : va_list arguments;
358 10 : va_start(arguments, model);
359 :
360 20 : while ((data = va_arg(arguments, const char *))) {
361 20 : arg_list.push_back(data);
362 : }
363 :
364 10 : va_end(arguments);
365 :
366 10 : {
367 10 : ML_TRAIN_GET_VALID_MODEL_LOCKED(nnmodel, model);
368 10 : ML_TRAIN_ADOPT_LOCK(nnmodel, model_lock);
369 10 : m = nnmodel->model;
370 : }
371 :
372 46 : returnable f = [&]() { return m->train(arg_list); };
373 10 : status = nntrainer_exception_boundary(f);
374 :
375 10 : return status;
376 : }
377 :
378 4 : int ml_train_model_run_with_single_param(ml_train_model_h model,
379 : const char *single_param) {
380 4 : ML_TRAIN_VERIFY_VALID_HANDLE(model);
381 :
382 4 : return ml_train_model_run(model, single_param, NULL);
383 : }
384 :
385 47 : int ml_train_model_destroy(ml_train_model_h model) {
386 47 : int status = ML_ERROR_NONE;
387 47 : ml_train_model *nnmodel;
388 :
389 47 : check_feature_state();
390 :
391 47 : {
392 93 : ML_TRAIN_GET_VALID_MODEL_LOCKED_RESET(nnmodel, model);
393 46 : ML_TRAIN_ADOPT_LOCK(nnmodel, model_lock);
394 : }
395 :
396 46 : if (nnmodel->optimizer) {
397 6 : if (nnmodel->optimizer->lr_scheduler) {
398 2 : ML_TRAIN_RESET_VALIDATED_HANDLE(nnmodel->optimizer->lr_scheduler);
399 4 : delete nnmodel->optimizer->lr_scheduler;
400 : }
401 :
402 6 : ML_TRAIN_RESET_VALIDATED_HANDLE(nnmodel->optimizer);
403 12 : delete nnmodel->optimizer;
404 : }
405 :
406 46 : if (nnmodel->dataset) {
407 6 : ML_TRAIN_RESET_VALIDATED_HANDLE(nnmodel->dataset);
408 12 : delete nnmodel->dataset;
409 : }
410 :
411 70 : for (auto &x : nnmodel->layers_map) {
412 24 : ML_TRAIN_RESET_VALIDATED_HANDLE(x.second);
413 48 : delete (x.second);
414 : }
415 46 : nnmodel->layers_map.clear();
416 :
417 46 : delete nnmodel;
418 :
419 46 : return status;
420 : }
421 :
422 16 : static int ml_train_model_get_summary_util(ml_train_model_h model,
423 : ml_train_summary_type_e verbosity,
424 : std::stringstream &ss) {
425 16 : int status = ML_ERROR_NONE;
426 16 : ml_train_model *nnmodel;
427 16 : std::shared_ptr<ml::train::Model> m;
428 :
429 16 : {
430 16 : ML_TRAIN_GET_VALID_MODEL_LOCKED(nnmodel, model);
431 16 : ML_TRAIN_ADOPT_LOCK(nnmodel, model_lock);
432 :
433 16 : m = nnmodel->model;
434 : }
435 :
436 32 : returnable f = [&]() {
437 16 : m->summarize(ss, verbosity);
438 16 : return ML_ERROR_NONE;
439 32 : };
440 :
441 16 : status = nntrainer_exception_boundary(f);
442 16 : return status;
443 : }
444 :
445 17 : int ml_train_model_get_summary(ml_train_model_h model,
446 : ml_train_summary_type_e verbosity,
447 : char **summary) {
448 17 : int status = ML_ERROR_NONE;
449 17 : std::stringstream ss;
450 :
451 17 : check_feature_state();
452 :
453 17 : ML_TRAIN_VERIFY_VALID_HANDLE(model);
454 :
455 17 : if (summary == nullptr) {
456 1 : ml_loge("summary pointer is null");
457 : return ML_ERROR_INVALID_PARAMETER;
458 : }
459 :
460 16 : status = ml_train_model_get_summary_util(model, verbosity, ss);
461 16 : if (status != ML_ERROR_NONE) {
462 0 : ml_loge("failed make a summary: %d", status);
463 : return status;
464 : }
465 :
466 33 : std::string str = ss.str();
467 16 : const std::string::size_type size = str.size();
468 :
469 16 : if (size == 0) {
470 0 : ml_logw("summary is empty for the model!");
471 : }
472 :
473 16 : *summary = (char *)malloc((size + 1) * sizeof(char));
474 16 : if (*summary == nullptr) {
475 0 : ml_loge("failed to malloc");
476 : return ML_ERROR_OUT_OF_MEMORY;
477 : }
478 16 : std::memcpy(*summary, str.c_str(), size + 1);
479 :
480 16 : return status;
481 : }
482 :
483 25 : int ml_train_model_add_layer(ml_train_model_h model, ml_train_layer_h layer) {
484 25 : int status = ML_ERROR_NONE;
485 25 : ml_train_model *nnmodel;
486 25 : ml_train_layer *nnlayer;
487 :
488 25 : check_feature_state();
489 :
490 25 : ML_TRAIN_GET_VALID_MODEL_LOCKED(nnmodel, model);
491 50 : ML_TRAIN_ADOPT_LOCK(nnmodel, model_lock);
492 25 : ML_TRAIN_GET_VALID_LAYER_LOCKED(nnlayer, layer);
493 49 : ML_TRAIN_ADOPT_LOCK(nnlayer, layer_lock);
494 :
495 24 : if (nnlayer->in_use) {
496 0 : ml_loge("Layer already in use.");
497 : return ML_ERROR_INVALID_PARAMETER;
498 : }
499 :
500 24 : std::shared_ptr<ml::train::Model> m;
501 24 : std::shared_ptr<ml::train::Layer> l;
502 :
503 24 : m = nnmodel->model;
504 24 : l = nnlayer->layer;
505 :
506 24 : if (nnmodel->layers_map.count(l->getName())) {
507 2 : ml_loge("It is not allowed to add layer with same name: %s",
508 : l->getName().c_str());
509 2 : return ML_ERROR_INVALID_PARAMETER;
510 : }
511 :
512 90 : returnable f = [&]() { return m->addLayer(l); };
513 :
514 22 : status = nntrainer_exception_boundary(f);
515 22 : if (status != ML_ERROR_NONE)
516 : return status;
517 :
518 24 : nnmodel->layers_map.insert({l->getName(), nnlayer});
519 21 : nnlayer->in_use = true;
520 21 : return status;
521 : }
522 :
523 6 : int ml_train_model_set_optimizer(ml_train_model_h model,
524 : ml_train_optimizer_h optimizer) {
525 6 : int status = ML_ERROR_NONE;
526 6 : ml_train_model *nnmodel;
527 6 : ml_train_optimizer *nnopt;
528 :
529 6 : check_feature_state();
530 :
531 6 : ML_TRAIN_GET_VALID_MODEL_LOCKED(nnmodel, model);
532 12 : ML_TRAIN_ADOPT_LOCK(nnmodel, model_lock);
533 6 : ML_TRAIN_GET_VALID_OPT_LOCKED(nnopt, optimizer);
534 12 : ML_TRAIN_ADOPT_LOCK(nnopt, opt_lock);
535 :
536 6 : if (nnopt->in_use) {
537 0 : ml_loge("Optimizer already in use.");
538 : return ML_ERROR_INVALID_PARAMETER;
539 : }
540 :
541 6 : std::shared_ptr<ml::train::Model> m;
542 6 : std::shared_ptr<ml::train::Optimizer> opt;
543 :
544 6 : m = nnmodel->model;
545 6 : opt = nnopt->optimizer;
546 :
547 24 : returnable f = [&]() { return m->setOptimizer(opt); };
548 :
549 6 : status = nntrainer_exception_boundary(f);
550 6 : if (status == ML_ERROR_NONE) {
551 6 : nnopt->in_use = true;
552 6 : if (nnmodel->optimizer) {
553 0 : nnmodel->optimizer->in_use = false;
554 : }
555 6 : nnmodel->optimizer = nnopt;
556 : }
557 :
558 6 : return status;
559 : }
560 :
561 8 : int ml_train_model_set_dataset(ml_train_model_h model,
562 : ml_train_dataset_h dataset) {
563 8 : int status = ML_ERROR_NONE;
564 8 : ml_train_model *nnmodel;
565 8 : ml_train_dataset *nndataset;
566 :
567 8 : check_feature_state();
568 :
569 8 : ML_TRAIN_GET_VALID_MODEL_LOCKED(nnmodel, model);
570 16 : ML_TRAIN_ADOPT_LOCK(nnmodel, model_lock);
571 8 : ML_TRAIN_GET_VALID_DATASET_LOCKED(nndataset, dataset);
572 15 : ML_TRAIN_ADOPT_LOCK(nndataset, dataset_lock);
573 :
574 7 : if (nndataset->in_use) {
575 0 : ml_loge("Dataset already in use.");
576 : return ML_ERROR_INVALID_PARAMETER;
577 : }
578 :
579 7 : std::shared_ptr<ml::train::Model> m;
580 :
581 7 : m = nnmodel->model;
582 :
583 14 : returnable f = [&]() {
584 7 : auto &[train_set, valid_set, test_set] = nndataset->dataset;
585 7 : int status = ML_ERROR_NONE;
586 7 : status = m->setDataset(ml::train::DatasetModeType::MODE_TRAIN, train_set);
587 7 : if (status != ML_ERROR_NONE) {
588 : return status;
589 : }
590 :
591 7 : if (valid_set != nullptr) {
592 2 : status = m->setDataset(ml::train::DatasetModeType::MODE_VALID, valid_set);
593 2 : if (status != ML_ERROR_NONE) {
594 : return status;
595 : }
596 : }
597 :
598 7 : if (test_set != nullptr) {
599 0 : status = m->setDataset(ml::train::DatasetModeType::MODE_TEST, test_set);
600 0 : if (status != ML_ERROR_NONE) {
601 : return status;
602 : }
603 : }
604 : return status;
605 14 : };
606 :
607 7 : status = nntrainer_exception_boundary(f);
608 7 : if (status == ML_ERROR_NONE) {
609 7 : nndataset->in_use = true;
610 7 : if (nnmodel->dataset)
611 1 : nnmodel->dataset->in_use = false;
612 7 : nnmodel->dataset = nndataset;
613 : }
614 :
615 7 : return status;
616 : }
617 :
618 12 : int ml_train_model_get_layer(ml_train_model_h model, const char *layer_name,
619 : ml_train_layer_h *layer) {
620 12 : int status = ML_ERROR_NONE;
621 12 : ml_train_model *nnmodel;
622 :
623 12 : check_feature_state();
624 :
625 12 : ML_TRAIN_GET_VALID_MODEL_LOCKED(nnmodel, model);
626 24 : ML_TRAIN_ADOPT_LOCK(nnmodel, model_lock);
627 :
628 12 : std::unordered_map<std::string, ml_train_layer *>::iterator layer_iter =
629 24 : nnmodel->layers_map.find(std::string(layer_name));
630 : /** if layer found in layers_map, return layer */
631 12 : if (layer_iter != nnmodel->layers_map.end()) {
632 6 : *layer = layer_iter->second;
633 6 : return status;
634 : }
635 :
636 : /**
637 : * if layer not found in layers_map, get layer from model,
638 : * wrap it in struct nnlayer, add new entry in layer_map and then return
639 : */
640 12 : std::shared_ptr<ml::train::Model> m;
641 6 : std::shared_ptr<ml::train::Layer> l;
642 :
643 6 : m = nnmodel->model;
644 18 : returnable f = [&]() { return m->getLayer(layer_name, &l); };
645 6 : status = nntrainer_exception_boundary(f);
646 :
647 6 : if (status != ML_ERROR_NONE)
648 : return status;
649 :
650 3 : ml_train_layer *nnlayer = new ml_train_layer;
651 3 : nnlayer->magic = ML_NNTRAINER_MAGIC;
652 3 : nnlayer->layer = l;
653 3 : nnlayer->in_use = true;
654 3 : nnmodel->layers_map.insert({l->getName(), nnlayer});
655 :
656 3 : *layer = nnlayer;
657 3 : return status;
658 : }
659 :
660 48 : int ml_train_layer_create(ml_train_layer_h *layer, ml_train_layer_type_e type) {
661 48 : int status = ML_ERROR_NONE;
662 48 : ml_train_layer *nnlayer;
663 :
664 48 : check_feature_state();
665 :
666 48 : nnlayer = new ml_train_layer;
667 48 : nnlayer->magic = ML_NNTRAINER_MAGIC;
668 48 : nnlayer->in_use = false;
669 :
670 96 : returnable f = [&]() {
671 48 : nnlayer->layer = ml::train::createLayer((ml::train::LayerType)type);
672 47 : return ML_ERROR_NONE;
673 96 : };
674 :
675 48 : status = nntrainer_exception_boundary(f);
676 48 : if (status != ML_ERROR_NONE) {
677 2 : delete nnlayer;
678 1 : ml_loge("Error: Create layer failed");
679 : } else {
680 47 : *layer = nnlayer;
681 : }
682 :
683 48 : return status;
684 : }
685 :
686 28 : int ml_train_layer_destroy(ml_train_layer_h layer) {
687 28 : int status = ML_ERROR_NONE;
688 28 : ml_train_layer *nnlayer;
689 :
690 28 : check_feature_state();
691 :
692 28 : {
693 28 : ML_TRAIN_GET_VALID_LAYER_LOCKED_RESET(nnlayer, layer);
694 28 : ML_TRAIN_ADOPT_LOCK(nnlayer, layer_lock);
695 :
696 28 : if (nnlayer->in_use) {
697 2 : ml_loge("Cannot delete layer already added in a model."
698 : "Delete model will delete this layer.");
699 30 : return ML_ERROR_INVALID_PARAMETER;
700 : }
701 : }
702 :
703 26 : delete nnlayer;
704 :
705 26 : return status;
706 : }
707 :
708 65 : int ml_train_layer_set_property(ml_train_layer_h layer, ...) {
709 65 : int status = ML_ERROR_NONE;
710 65 : ml_train_layer *nnlayer;
711 65 : const char *data;
712 65 : std::shared_ptr<ml::train::Layer> l;
713 :
714 65 : check_feature_state();
715 :
716 65 : ML_TRAIN_VERIFY_VALID_HANDLE(layer);
717 :
718 64 : std::vector<std::string> arg_list;
719 64 : va_list arguments;
720 64 : va_start(arguments, layer);
721 :
722 183 : while ((data = va_arg(arguments, const char *))) {
723 238 : arg_list.push_back(data);
724 : }
725 :
726 64 : va_end(arguments);
727 :
728 64 : {
729 64 : ML_TRAIN_GET_VALID_LAYER_LOCKED(nnlayer, layer);
730 64 : ML_TRAIN_ADOPT_LOCK(nnlayer, layer_lock);
731 :
732 64 : l = nnlayer->layer;
733 : }
734 :
735 128 : returnable f = [&]() {
736 64 : l->setProperty(arg_list);
737 52 : return ML_ERROR_NONE;
738 128 : };
739 64 : status = nntrainer_exception_boundary(f);
740 :
741 64 : return status;
742 : }
743 :
744 3 : int ml_train_layer_set_property_with_single_param(ml_train_layer_h layer,
745 : const char *single_param) {
746 3 : ML_TRAIN_VERIFY_VALID_HANDLE(layer);
747 :
748 3 : return ml_train_layer_set_property(layer, single_param, NULL);
749 : }
750 :
751 20 : int ml_train_optimizer_create(ml_train_optimizer_h *optimizer,
752 : ml_train_optimizer_type_e type) {
753 20 : int status = ML_ERROR_NONE;
754 :
755 20 : check_feature_state();
756 :
757 20 : ml_train_optimizer *nnopt = new ml_train_optimizer;
758 20 : nnopt->magic = ML_NNTRAINER_MAGIC;
759 20 : nnopt->in_use = false;
760 20 : nnopt->lr_scheduler = NULL;
761 :
762 40 : returnable f = [&]() {
763 39 : nnopt->optimizer =
764 20 : ml::train::createOptimizer((ml::train::OptimizerType)type);
765 19 : return ML_ERROR_NONE;
766 40 : };
767 :
768 20 : status = nntrainer_exception_boundary(f);
769 20 : if (status != ML_ERROR_NONE) {
770 2 : delete nnopt;
771 1 : ml_loge("creating optimizer failed");
772 : } else {
773 19 : *optimizer = nnopt;
774 : }
775 :
776 20 : return status;
777 : }
778 :
779 14 : int ml_train_optimizer_destroy(ml_train_optimizer_h optimizer) {
780 14 : int status = ML_ERROR_NONE;
781 14 : ml_train_optimizer *nnopt;
782 :
783 14 : check_feature_state();
784 :
785 14 : {
786 27 : ML_TRAIN_GET_VALID_OPT_LOCKED_RESET(nnopt, optimizer);
787 13 : ML_TRAIN_ADOPT_LOCK(nnopt, optimizer_lock);
788 : }
789 :
790 13 : if (nnopt->in_use) {
791 1 : ml_loge("Cannot delete optimizer already set to a model."
792 : "Delete model will delete this optimizer.");
793 1 : return ML_ERROR_INVALID_PARAMETER;
794 : }
795 :
796 12 : if (nnopt->lr_scheduler) {
797 2 : ML_TRAIN_RESET_VALIDATED_HANDLE(nnopt->lr_scheduler);
798 4 : delete nnopt->lr_scheduler;
799 : }
800 :
801 12 : delete nnopt;
802 12 : return status;
803 : }
804 :
805 16 : int ml_train_optimizer_set_property(ml_train_optimizer_h optimizer, ...) {
806 16 : int status = ML_ERROR_NONE;
807 16 : ml_train_optimizer *nnopt;
808 16 : const char *data;
809 16 : std::shared_ptr<ml::train::Optimizer> opt;
810 :
811 16 : check_feature_state();
812 :
813 16 : ML_TRAIN_VERIFY_VALID_HANDLE(optimizer);
814 :
815 15 : std::vector<std::string> arg_list;
816 15 : va_list arguments;
817 15 : va_start(arguments, optimizer);
818 :
819 70 : while ((data = va_arg(arguments, const char *))) {
820 110 : arg_list.push_back(data);
821 : }
822 :
823 15 : va_end(arguments);
824 :
825 15 : {
826 15 : ML_TRAIN_GET_VALID_OPT_LOCKED(nnopt, optimizer);
827 15 : ML_TRAIN_ADOPT_LOCK(nnopt, optimizer_lock);
828 :
829 15 : opt = nnopt->optimizer;
830 : }
831 :
832 30 : returnable f = [&]() {
833 15 : opt->setProperty(arg_list);
834 11 : return ML_ERROR_NONE;
835 30 : };
836 :
837 15 : status = nntrainer_exception_boundary(f);
838 :
839 15 : return status;
840 : }
841 :
842 3 : int ml_train_optimizer_set_property_with_single_param(
843 : ml_train_optimizer_h optimizer, const char *single_param) {
844 3 : ML_TRAIN_VERIFY_VALID_HANDLE(optimizer);
845 :
846 3 : return ml_train_optimizer_set_property(optimizer, single_param, NULL);
847 : }
848 :
849 4 : int ml_train_optimizer_set_lr_scheduler(ml_train_optimizer_h optimizer,
850 : ml_train_lr_scheduler_h lr_scheduler) {
851 4 : int status = ML_ERROR_NONE;
852 4 : ml_train_optimizer *nnopt;
853 4 : ml_train_lr_scheduler *nnlrscheduler;
854 :
855 4 : check_feature_state();
856 :
857 4 : std::shared_ptr<ml::train::Optimizer> opt;
858 4 : std::shared_ptr<ml::train::LearningRateScheduler> lr_sched;
859 :
860 4 : {
861 4 : ML_TRAIN_GET_VALID_OPT_LOCKED(nnopt, optimizer);
862 4 : ML_TRAIN_ADOPT_LOCK(nnopt, opt_lock);
863 4 : opt = nnopt->optimizer;
864 : }
865 :
866 4 : {
867 4 : ML_TRAIN_GET_VALID_LR_SCHEDULER_LOCKED(nnlrscheduler, lr_scheduler);
868 4 : ML_TRAIN_ADOPT_LOCK(nnlrscheduler, lr_scheduler_lock);
869 4 : lr_sched = nnlrscheduler->lr_scheduler;
870 : }
871 :
872 4 : if (nnlrscheduler->in_use) {
873 0 : ml_loge("learning rate scheduler already in use.");
874 : return ML_ERROR_INVALID_PARAMETER;
875 : }
876 :
877 16 : returnable f = [&]() { return opt->setLearningRateScheduler(lr_sched); };
878 :
879 4 : status = nntrainer_exception_boundary(f);
880 4 : if (status == ML_ERROR_NONE) {
881 4 : nnlrscheduler->in_use = true;
882 4 : if (nnopt->lr_scheduler) {
883 0 : nnopt->lr_scheduler->in_use = false;
884 : }
885 4 : nnopt->lr_scheduler = nnlrscheduler;
886 : }
887 :
888 4 : return status;
889 : }
890 :
891 20 : int ml_train_lr_scheduler_create(ml_train_lr_scheduler_h *lr_scheduler,
892 : ml_train_lr_scheduler_type_e type) {
893 20 : int status = ML_ERROR_NONE;
894 :
895 20 : check_feature_state();
896 :
897 20 : ml_train_lr_scheduler *nnlrscheduler = new ml_train_lr_scheduler;
898 20 : nnlrscheduler->magic = ML_NNTRAINER_MAGIC;
899 20 : nnlrscheduler->in_use = false;
900 :
901 40 : returnable f = [&]() {
902 20 : nnlrscheduler->lr_scheduler = ml::train::createLearningRateScheduler(
903 20 : (ml::train::LearningRateSchedulerType)type);
904 19 : return ML_ERROR_NONE;
905 40 : };
906 :
907 20 : status = nntrainer_exception_boundary(f);
908 20 : if (status != ML_ERROR_NONE) {
909 2 : delete nnlrscheduler;
910 1 : ml_loge("creating optimizer failed");
911 : } else {
912 19 : *lr_scheduler = nnlrscheduler;
913 : }
914 :
915 20 : return status;
916 : }
917 :
918 18 : int ml_train_lr_scheduler_destroy(ml_train_lr_scheduler_h lr_scheduler) {
919 18 : int status = ML_ERROR_NONE;
920 18 : ml_train_lr_scheduler *nnlrscheduler;
921 :
922 18 : check_feature_state();
923 :
924 18 : {
925 18 : ML_TRAIN_GET_VALID_LR_SCHEDULER_LOCKED_RESET(nnlrscheduler, lr_scheduler);
926 17 : ML_TRAIN_ADOPT_LOCK(nnlrscheduler, lr_scheduler_lock);
927 :
928 17 : if (nnlrscheduler->in_use) {
929 2 : ml_loge(
930 : "Cannot delete learning rate scheduler already set to a optimizer."
931 : "Delete optimizer will delete this learning rate scheduler.");
932 20 : return ML_ERROR_INVALID_PARAMETER;
933 : }
934 : }
935 :
936 15 : delete nnlrscheduler;
937 15 : return status;
938 : }
939 :
940 14 : int ml_train_lr_scheduler_set_property(ml_train_lr_scheduler_h lr_scheduler,
941 : ...) {
942 14 : int status = ML_ERROR_NONE;
943 14 : ml_train_lr_scheduler *nnlrscheduler;
944 14 : const char *data;
945 14 : std::shared_ptr<ml::train::LearningRateScheduler> lr_sched;
946 :
947 14 : check_feature_state();
948 :
949 14 : ML_TRAIN_VERIFY_VALID_HANDLE(lr_scheduler);
950 :
951 14 : std::vector<std::string> arg_list;
952 14 : va_list arguments;
953 14 : va_start(arguments, lr_scheduler);
954 :
955 41 : while ((data = va_arg(arguments, const char *))) {
956 54 : arg_list.push_back(data);
957 : }
958 :
959 14 : va_end(arguments);
960 :
961 14 : {
962 14 : ML_TRAIN_GET_VALID_LR_SCHEDULER_LOCKED(nnlrscheduler, lr_scheduler);
963 14 : ML_TRAIN_ADOPT_LOCK(nnlrscheduler, lr_scheduler_lock);
964 :
965 14 : lr_sched = nnlrscheduler->lr_scheduler;
966 : }
967 :
968 28 : returnable f = [&]() {
969 14 : lr_sched->setProperty(arg_list);
970 6 : return ML_ERROR_NONE;
971 28 : };
972 :
973 14 : status = nntrainer_exception_boundary(f);
974 :
975 14 : return status;
976 : }
977 :
978 3 : int ml_train_lr_scheduler_set_property_with_single_param(
979 : ml_train_lr_scheduler_h lr_scheduler, const char *single_param) {
980 3 : ML_TRAIN_VERIFY_VALID_HANDLE(lr_scheduler);
981 :
982 3 : return ml_train_lr_scheduler_set_property(lr_scheduler, single_param, NULL);
983 : }
984 :
985 15 : int ml_train_dataset_create(ml_train_dataset_h *dataset) {
986 15 : return ml_train_dataset_create(dataset, ml::train::DatasetType::UNKNOWN,
987 15 : nullptr, nullptr, nullptr);
988 : }
989 :
990 15 : int ml_train_dataset_add_generator(ml_train_dataset_h dataset,
991 : ml_train_dataset_mode_e mode,
992 : ml_train_datagen_cb cb, void *user_data) {
993 15 : check_feature_state();
994 15 : if (cb == nullptr) {
995 : return ML_ERROR_INVALID_PARAMETER;
996 : }
997 :
998 12 : return ml_train_dataset_add_(dataset, mode, ml::train::DatasetType::GENERATOR,
999 12 : cb, user_data);
1000 : }
1001 :
1002 9 : int ml_train_dataset_add_file(ml_train_dataset_h dataset,
1003 : ml_train_dataset_mode_e mode, const char *file) {
1004 9 : check_feature_state();
1005 9 : if (file == nullptr) {
1006 : return ML_ERROR_INVALID_PARAMETER;
1007 : }
1008 :
1009 5 : return ml_train_dataset_add_(dataset, mode, ml::train::DatasetType::FILE,
1010 5 : file);
1011 : }
1012 :
1013 16 : int ml_train_dataset_create_with_generator(ml_train_dataset_h *dataset,
1014 : ml_train_datagen_cb train_cb,
1015 : ml_train_datagen_cb valid_cb,
1016 : ml_train_datagen_cb test_cb) {
1017 16 : if (train_cb == nullptr) {
1018 : return ML_ERROR_INVALID_PARAMETER;
1019 : }
1020 11 : return ml_train_dataset_create(dataset, ml::train::DatasetType::GENERATOR,
1021 11 : train_cb, valid_cb, test_cb);
1022 : }
1023 :
1024 13 : int ml_train_dataset_create_with_file(ml_train_dataset_h *dataset,
1025 : const char *train_file,
1026 : const char *valid_file,
1027 : const char *test_file) {
1028 13 : if (train_file == nullptr) {
1029 : return ML_ERROR_INVALID_PARAMETER;
1030 : }
1031 8 : return ml_train_dataset_create(dataset, ml::train::DatasetType::FILE,
1032 8 : train_file, valid_file, test_file);
1033 : }
1034 :
1035 : /**
1036 : * @brief set property for the specific data mode, main difference from @a
1037 : * ml_train_dataset_set_property_for_mode() is that this function returns @a
1038 : * ML_ERROR_NOT_SUPPORTED if dataset does not exist.
1039 : *
1040 : * @param[in] dataset dataset
1041 : * @param[in] mode mode
1042 : * @param[in] args argument
1043 : * @retval #ML_ERROR_NONE successful
1044 : * @retval #ML_ERROR_INVALID_PARAMETER when arg is invalid
1045 : * @retval #ML_ERROR_NOT_SUPPORTED when dataset did not exist
1046 : */
1047 : static int
1048 37 : ml_train_dataset_set_property_for_mode_(ml_train_dataset_h dataset,
1049 : ml_train_dataset_mode_e mode,
1050 : const std::vector<void *> &args) {
1051 37 : static constexpr char USER_DATA[] = "user_data";
1052 37 : int status = ML_ERROR_NONE;
1053 37 : ml_train_dataset *nndataset;
1054 :
1055 37 : check_feature_state();
1056 :
1057 37 : ML_TRAIN_VERIFY_VALID_HANDLE(dataset);
1058 :
1059 35 : {
1060 35 : ML_TRAIN_GET_VALID_DATASET_LOCKED(nndataset, dataset);
1061 35 : ML_TRAIN_ADOPT_LOCK(nndataset, dataset_lock);
1062 :
1063 35 : auto &db = nndataset->dataset[mode];
1064 :
1065 133 : returnable f = [&db, &args]() {
1066 35 : int status_ = ML_ERROR_NONE;
1067 35 : if (db == nullptr) {
1068 34 : status_ = ML_ERROR_NOT_SUPPORTED;
1069 : return status_;
1070 : }
1071 :
1072 39 : std::vector<std::string> properties;
1073 38 : for (unsigned int i = 0; i < args.size(); ++i) {
1074 20 : char *key_ptr = (char *)args[i];
1075 24 : std::string key = key_ptr;
1076 20 : std::for_each(key.begin(), key.end(),
1077 278 : [](char &c) { c = ::tolower(c); });
1078 20 : key.erase(std::remove_if(key.begin(), key.end(), ::isspace), key.end());
1079 :
1080 : /** Handle the user_data as a special case, serialize the address and
1081 : * pass it to the databuffer */
1082 20 : if (key == USER_DATA) {
1083 : /** This ensures that a valid user_data element is passed by the user
1084 : */
1085 4 : if (i + 1 >= args.size()) {
1086 1 : ml_loge("key user_data expects, next value to be a pointer");
1087 1 : status_ = ML_ERROR_INVALID_PARAMETER;
1088 1 : return status_;
1089 : }
1090 3 : std::ostringstream ss;
1091 3 : ss << key << '=' << args[i + 1];
1092 3 : properties.push_back(ss.str());
1093 :
1094 : /** As values of i+1 is consumed, increase i by 1 */
1095 3 : i++;
1096 16 : } else if (key.rfind("user_data=", 0) == 0) {
1097 : /** case that user tries to pass something like user_data=5, this is
1098 : * not allowed */
1099 2 : status_ = ML_ERROR_INVALID_PARAMETER;
1100 : return status_;
1101 : } else {
1102 15 : properties.push_back(key);
1103 15 : continue;
1104 : }
1105 : }
1106 :
1107 18 : db->setProperty(properties);
1108 : return status_;
1109 70 : };
1110 :
1111 35 : status = nntrainer_exception_boundary(f);
1112 : }
1113 35 : return status;
1114 : }
1115 :
1116 11 : int ml_train_dataset_set_property(ml_train_dataset_h dataset, ...) {
1117 22 : std::vector<void *> arg_list;
1118 11 : va_list arguments;
1119 11 : va_start(arguments, dataset);
1120 :
1121 23 : void *data;
1122 23 : while ((data = va_arg(arguments, void *))) {
1123 12 : arg_list.push_back(data);
1124 : }
1125 11 : va_end(arguments);
1126 :
1127 : /// having status of ML_ERROR_NOT_SUPPORTED is not an error in this call.
1128 11 : int status = ml_train_dataset_set_property_for_mode_(
1129 : dataset, ML_TRAIN_DATASET_MODE_TRAIN, arg_list);
1130 11 : if (status != ML_ERROR_NONE && status != ML_ERROR_NOT_SUPPORTED) {
1131 : return status;
1132 : }
1133 :
1134 6 : status = ml_train_dataset_set_property_for_mode_(
1135 : dataset, ML_TRAIN_DATASET_MODE_VALID, arg_list);
1136 6 : if (status != ML_ERROR_NONE && status != ML_ERROR_NOT_SUPPORTED) {
1137 : return status;
1138 : }
1139 :
1140 6 : status = ml_train_dataset_set_property_for_mode_(
1141 : dataset, ML_TRAIN_DATASET_MODE_TEST, arg_list);
1142 6 : if (status != ML_ERROR_NONE && status != ML_ERROR_NOT_SUPPORTED) {
1143 0 : return status;
1144 : }
1145 :
1146 : return ML_ERROR_NONE;
1147 : }
1148 :
1149 14 : int ml_train_dataset_set_property_for_mode(ml_train_dataset_h dataset,
1150 : ml_train_dataset_mode_e mode, ...) {
1151 14 : std::vector<void *> arg_list;
1152 14 : va_list arguments;
1153 14 : va_start(arguments, mode);
1154 :
1155 30 : void *data;
1156 30 : while ((data = va_arg(arguments, void *))) {
1157 16 : arg_list.push_back(data);
1158 : }
1159 14 : va_end(arguments);
1160 :
1161 14 : int status = ml_train_dataset_set_property_for_mode_(dataset, mode, arg_list);
1162 :
1163 37 : return status != ML_ERROR_NONE ? ML_ERROR_INVALID_PARAMETER : ML_ERROR_NONE;
1164 : }
1165 :
1166 4 : int ml_train_dataset_set_property_for_mode_with_single_param(
1167 : ml_train_dataset_h dataset, ml_train_dataset_mode_e mode,
1168 : const char *single_param) {
1169 4 : ML_TRAIN_VERIFY_VALID_HANDLE(dataset);
1170 :
1171 4 : return ml_train_dataset_set_property_for_mode(dataset, mode, single_param,
1172 4 : NULL);
1173 : }
1174 :
1175 29 : int ml_train_dataset_destroy(ml_train_dataset_h dataset) {
1176 29 : int status = ML_ERROR_NONE;
1177 29 : ml_train_dataset *nndataset;
1178 :
1179 29 : check_feature_state();
1180 :
1181 29 : {
1182 29 : ML_TRAIN_GET_VALID_DATASET_LOCKED_RESET(nndataset, dataset);
1183 28 : ML_TRAIN_ADOPT_LOCK(nndataset, dataset_lock);
1184 :
1185 28 : if (nndataset->in_use) {
1186 2 : ml_loge("Cannot delete dataset already set to a model."
1187 : "Delete model will delete this dataset.");
1188 31 : return ML_ERROR_INVALID_PARAMETER;
1189 : }
1190 : }
1191 :
1192 26 : delete nndataset;
1193 26 : return status;
1194 : }
1195 :
1196 6 : int ml_train_model_get_input_tensors_info(ml_train_model_h model,
1197 : ml_tensors_info_h *info) {
1198 6 : int status = ML_ERROR_NONE;
1199 6 : ml_train_model *nnmodel;
1200 6 : std::shared_ptr<ml::train::Model> m;
1201 12 : returnable f;
1202 :
1203 6 : check_feature_state();
1204 :
1205 6 : if (!info) {
1206 : return ML_ERROR_INVALID_PARAMETER;
1207 : }
1208 :
1209 6 : ML_TRAIN_GET_VALID_MODEL_LOCKED(nnmodel, model);
1210 10 : ML_TRAIN_ADOPT_LOCK(nnmodel, model_lock);
1211 4 : m = nnmodel->model;
1212 4 : if (m == NULL) {
1213 : return ML_ERROR_INVALID_PARAMETER;
1214 : }
1215 :
1216 8 : std::vector<ml::train::TensorDim> dims;
1217 4 : f = [&]() {
1218 4 : dims = m->getInputDimension();
1219 3 : return ML_ERROR_NONE;
1220 4 : };
1221 4 : status = nntrainer_exception_boundary(f);
1222 4 : if (status != ML_ERROR_NONE) {
1223 : return status;
1224 : }
1225 :
1226 3 : status = ml_tensors_info_create(info);
1227 3 : if (status != ML_ERROR_NONE) {
1228 : return status;
1229 : }
1230 :
1231 3 : status = ml_tensors_info_set_count(*info, dims.size());
1232 3 : if (status != ML_ERROR_NONE) {
1233 0 : ml_tensors_info_destroy(*info);
1234 : return status;
1235 : }
1236 :
1237 6 : for (unsigned int i = 0; i < dims.size(); ++i) {
1238 3 : status = ml_tensors_info_set_tensor_type(*info, i, ML_TENSOR_TYPE_FLOAT32);
1239 3 : if (status != ML_ERROR_NONE) {
1240 0 : ml_tensors_info_destroy(*info);
1241 0 : return status;
1242 : }
1243 :
1244 6 : std::vector<unsigned int> u_dim;
1245 :
1246 15 : for (unsigned int j = 0; j < dims[i].getNumDim(); j++)
1247 12 : u_dim.push_back(dims[i].getDim()[j]);
1248 :
1249 3 : status = ml_tensors_info_set_tensor_dimension(*info, i, u_dim.data());
1250 3 : if (status != ML_ERROR_NONE) {
1251 0 : ml_tensors_info_destroy(*info);
1252 0 : return status;
1253 : }
1254 : }
1255 :
1256 : return status;
1257 : }
1258 :
1259 6 : int ml_train_model_get_output_tensors_info(ml_train_model_h model,
1260 : ml_tensors_info_h *info) {
1261 6 : int status = ML_ERROR_NONE;
1262 6 : ml_train_model *nnmodel;
1263 6 : std::shared_ptr<ml::train::Model> m;
1264 12 : returnable f;
1265 :
1266 6 : check_feature_state();
1267 :
1268 6 : if (!info) {
1269 : return ML_ERROR_INVALID_PARAMETER;
1270 : }
1271 :
1272 6 : ML_TRAIN_GET_VALID_MODEL_LOCKED(nnmodel, model);
1273 10 : ML_TRAIN_ADOPT_LOCK(nnmodel, model_lock);
1274 4 : m = nnmodel->model;
1275 4 : if (m == NULL) {
1276 : return ML_ERROR_INVALID_PARAMETER;
1277 : }
1278 :
1279 8 : std::vector<ml::train::TensorDim> dims;
1280 :
1281 4 : f = [&]() {
1282 4 : dims = m->getOutputDimension();
1283 3 : return ML_ERROR_NONE;
1284 4 : };
1285 4 : status = nntrainer_exception_boundary(f);
1286 4 : if (status != ML_ERROR_NONE) {
1287 : return status;
1288 : }
1289 :
1290 3 : status = ml_tensors_info_create(info);
1291 3 : if (status != ML_ERROR_NONE) {
1292 : return status;
1293 : }
1294 :
1295 3 : status = ml_tensors_info_set_count(*info, dims.size());
1296 3 : if (status != ML_ERROR_NONE) {
1297 0 : ml_tensors_info_destroy(*info);
1298 : return status;
1299 : }
1300 :
1301 6 : for (unsigned int i = 0; i < dims.size(); ++i) {
1302 3 : status = ml_tensors_info_set_tensor_type(*info, i, ML_TENSOR_TYPE_FLOAT32);
1303 3 : if (status != ML_ERROR_NONE) {
1304 0 : ml_tensors_info_destroy(*info);
1305 0 : return status;
1306 : }
1307 :
1308 6 : std::vector<unsigned int> u_dim;
1309 :
1310 15 : for (unsigned int j = 0; j < dims[i].getNumDim(); j++)
1311 12 : u_dim.push_back(dims[i].getDim()[j]);
1312 :
1313 3 : status = ml_tensors_info_set_tensor_dimension(*info, i, u_dim.data());
1314 3 : if (status != ML_ERROR_NONE) {
1315 0 : ml_tensors_info_destroy(*info);
1316 0 : return status;
1317 : }
1318 : }
1319 :
1320 : return status;
1321 : }
1322 :
1323 0 : int ml_train_model_save(ml_train_model_h model, const char *file_path,
1324 : ml_train_model_format_e format) {
1325 0 : int status = ML_ERROR_NONE;
1326 0 : ml_train_model *nnmodel;
1327 0 : std::shared_ptr<ml::train::Model> m;
1328 :
1329 0 : {
1330 0 : ML_TRAIN_GET_VALID_MODEL_LOCKED(nnmodel, model);
1331 0 : ML_TRAIN_ADOPT_LOCK(nnmodel, model_lock);
1332 :
1333 0 : m = nnmodel->model;
1334 : }
1335 :
1336 0 : returnable f = [&]() {
1337 0 : m->save(file_path, static_cast<ml::train::ModelFormat>(format));
1338 0 : return ML_ERROR_NONE;
1339 0 : };
1340 :
1341 0 : status = nntrainer_exception_boundary(f);
1342 0 : return status;
1343 : }
1344 :
1345 0 : int ml_train_model_load(ml_train_model_h model, const char *file_path,
1346 : ml_train_model_format_e format) {
1347 0 : int status = ML_ERROR_NONE;
1348 0 : ml_train_model *nnmodel;
1349 0 : std::shared_ptr<ml::train::Model> m;
1350 :
1351 0 : {
1352 0 : ML_TRAIN_GET_VALID_MODEL_LOCKED(nnmodel, model);
1353 0 : ML_TRAIN_ADOPT_LOCK(nnmodel, model_lock);
1354 :
1355 0 : m = nnmodel->model;
1356 : }
1357 :
1358 0 : returnable f = [&]() {
1359 0 : m->load(file_path, static_cast<ml::train::ModelFormat>(format));
1360 0 : return ML_ERROR_NONE;
1361 0 : };
1362 :
1363 0 : status = nntrainer_exception_boundary(f);
1364 0 : return status;
1365 : }
1366 :
1367 1 : int ml_train_model_get_weight(ml_train_model_h model, const char *layer_name,
1368 : ml_tensors_data_h *weight,
1369 : ml_tensors_info_h *info) {
1370 1 : int status = ML_ERROR_NONE;
1371 1 : ml_train_model *nnmodel;
1372 :
1373 1 : check_feature_state();
1374 :
1375 1 : ML_TRAIN_GET_VALID_MODEL_LOCKED(nnmodel, model);
1376 2 : ML_TRAIN_ADOPT_LOCK(nnmodel, model_lock);
1377 :
1378 1 : std::shared_ptr<ml::train::Model> m;
1379 1 : std::shared_ptr<ml::train::Layer> l;
1380 2 : std::vector<float *> w;
1381 1 : std::vector<ml::train::TensorDim> dims;
1382 1 : std::vector<std::string> weight_name;
1383 :
1384 1 : m = nnmodel->model;
1385 :
1386 3 : returnable f = [&]() { return m->getLayer(layer_name, &l); };
1387 1 : status = nntrainer_exception_boundary(f);
1388 1 : if (status != ML_ERROR_NONE)
1389 : return status;
1390 :
1391 2 : f = [&]() {
1392 1 : l->getWeights(w, dims);
1393 :
1394 3 : for (unsigned int i = 0; i < dims.size(); ++i)
1395 2 : weight_name.emplace_back(l->getWeightName(i));
1396 :
1397 1 : return ML_ERROR_NONE;
1398 1 : };
1399 :
1400 1 : status = nntrainer_exception_boundary(f);
1401 1 : if (status != ML_ERROR_NONE) {
1402 : return status;
1403 : }
1404 :
1405 1 : status = ml_tensors_info_create(info);
1406 1 : if (status != ML_ERROR_NONE) {
1407 : return status;
1408 : }
1409 :
1410 1 : status = ml_tensors_info_set_count(*info, dims.size());
1411 1 : if (status != ML_ERROR_NONE) {
1412 0 : ml_tensors_info_destroy(*info);
1413 : return status;
1414 : }
1415 :
1416 3 : for (unsigned int i = 0; i < dims.size(); ++i) {
1417 2 : status = ml_tensors_info_set_tensor_type(*info, i, ML_TENSOR_TYPE_FLOAT32);
1418 2 : if (status != ML_ERROR_NONE) {
1419 0 : ml_tensors_info_destroy(*info);
1420 0 : return status;
1421 : }
1422 :
1423 4 : std::vector<unsigned int> u_dim;
1424 :
1425 10 : for (unsigned int j = 0; j < dims[i].getNumDim(); j++)
1426 8 : u_dim.push_back(dims[i].getDim()[j]);
1427 :
1428 2 : status = ml_tensors_info_set_tensor_dimension(*info, i, u_dim.data());
1429 2 : if (status != ML_ERROR_NONE) {
1430 0 : ml_tensors_info_destroy(*info);
1431 0 : return status;
1432 : }
1433 :
1434 2 : status = ml_tensors_info_set_tensor_name(*info, i, weight_name[i].c_str());
1435 2 : if (status != ML_ERROR_NONE) {
1436 0 : ml_tensors_info_destroy(*info);
1437 : return status;
1438 : }
1439 : }
1440 :
1441 1 : status = ml_tensors_data_create(*info, weight);
1442 1 : if (status != ML_ERROR_NONE) {
1443 0 : ml_tensors_data_destroy(*weight);
1444 : return status;
1445 : }
1446 :
1447 3 : for (unsigned int i = 0; i < dims.size(); ++i) {
1448 6 : status = ml_tensors_data_set_tensor_data(
1449 2 : *weight, i, w[i], dims[i].getDataLen() * sizeof(float));
1450 2 : if (status != ML_ERROR_NONE) {
1451 0 : ml_tensors_data_destroy(*weight);
1452 : return status;
1453 : }
1454 : }
1455 :
1456 : return status;
1457 : }
1458 :
1459 : #ifdef __cplusplus
1460 : }
1461 : #endif
|