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 <algorithm>
26 : #include <array>
27 : #include <cstdarg>
28 : #include <cstring>
29 : #include <nntrainer.h>
30 : #include <nntrainer_internal.h>
31 : #include <sstream>
32 : #include <string>
33 :
34 : #include <nntrainer_error.h>
35 : #include <nntrainer_log.h>
36 :
37 : /**
38 : * @brief Global lock for nntrainer C-API
39 : * @details This lock ensures that ml_train_model_destroy is thread safe. All
40 : * other API functions use the mutex from their object handle. However
41 : * for destroy, object mutex cannot be used as their handles are
42 : * destroyed at destroy.
43 : */
44 : std::mutex GLOCK;
45 :
46 : /**
47 : * @brief Adopt the lock to the current scope for the object
48 : */
49 : #define ML_TRAIN_ADOPT_LOCK(obj, obj_lock) \
50 : std::lock_guard<std::mutex> obj_lock(obj->m, std::adopt_lock)
51 :
52 : /**
53 : * @brief function to wrap an exception to predefined error value
54 : * @param[in] func must be wrapped inside lambda []() -> int otherwise compile
55 : * error will be raised
56 : * @retval errorno
57 : */
58 530 : template <typename F> static int nntrainer_exception_boundary(F &&func) {
59 : int status = ML_ERROR_NONE;
60 :
61 : /**< Exception boundary for cpp exceptions */
62 : /// @note aware that some exception are inheritance of others so should be
63 : /// caught before than some
64 : try {
65 : status = func();
66 45 : } catch (nntrainer::exception::not_supported &e) {
67 4 : ml_loge("%s %s", typeid(e).name(), e.what());
68 : return ML_ERROR_INVALID_PARAMETER;
69 0 : } catch (nntrainer::exception::permission_denied &e) {
70 0 : ml_loge("%s %s", typeid(e).name(), e.what());
71 : return ML_ERROR_PERMISSION_DENIED;
72 38 : } catch (std::invalid_argument &e) {
73 76 : ml_loge("%s %s", typeid(e).name(), e.what());
74 : return ML_ERROR_INVALID_PARAMETER;
75 0 : } catch (std::range_error &e) {
76 0 : ml_loge("%s %s", typeid(e).name(), e.what());
77 : return ML_ERROR_INVALID_PARAMETER;
78 3 : } catch (std::out_of_range &e) {
79 6 : ml_loge("%s %s", typeid(e).name(), e.what());
80 : return ML_ERROR_INVALID_PARAMETER;
81 2 : } catch (std::logic_error &e) {
82 4 : ml_loge("%s %s", typeid(e).name(), e.what());
83 : return ML_ERROR_INVALID_PARAMETER;
84 0 : } catch (std::bad_alloc &e) {
85 0 : ml_loge("%s %s", typeid(e).name(), e.what());
86 : return ML_ERROR_OUT_OF_MEMORY;
87 0 : } catch (std::exception &e) {
88 0 : ml_loge("%s %s", typeid(e).name(), e.what());
89 : return ML_ERROR_UNKNOWN;
90 0 : } catch (...) {
91 0 : ml_loge("unknown error type thrown");
92 : return ML_ERROR_UNKNOWN;
93 : }
94 :
95 : /**< Exception boundary for specialized error code */
96 : /// @todo deprecate this with #233
97 485 : switch (status) {
98 : case ML_ERROR_BAD_ADDRESS:
99 : return ML_ERROR_OUT_OF_MEMORY;
100 : case ML_ERROR_RESULT_OUT_OF_RANGE:
101 : return ML_ERROR_INVALID_PARAMETER;
102 : default:
103 : return status;
104 : }
105 : }
106 :
107 : typedef std::function<int()> returnable;
108 :
109 : /**
110 : * @brief std::make_shared wrapped with exception boundary
111 : *
112 : * @tparam Tv value type.
113 : * @tparam Tp pointer type.
114 : * @tparam Types args used to construct
115 : * @param target pointer
116 : * @param args args
117 : * @return int error value. ML_ERROR_OUT_OF_MEMORY if fail
118 : */
119 : template <typename Tv, typename Tp, typename... Types>
120 : static int exception_bounded_make_shared(Tp &target, Types... args) {
121 : returnable f = [&]() {
122 : target = std::make_shared<Tv>(args...);
123 : return ML_ERROR_NONE;
124 : };
125 :
126 : return nntrainer_exception_boundary(f);
127 : }
128 :
129 : /**
130 : * @brief Create dataset with different types of train/test/valid data source
131 : * @param[in] dataset dataset object to be created
132 : * @param[in] type type of the dataset
133 : * @param[in] train training data source
134 : * @param[in] valid validation data source
135 : * @param[in] test testing data source
136 : */
137 : template <typename T>
138 33 : static int ml_train_dataset_create(ml_train_dataset_h *dataset,
139 : ml::train::DatasetType type, T train,
140 : T valid, T test) {
141 : int status = ML_ERROR_NONE;
142 :
143 : check_feature_state();
144 33 : if (dataset == NULL) {
145 : return ML_ERROR_INVALID_PARAMETER;
146 : }
147 :
148 32 : ml_train_dataset *nndataset = new ml_train_dataset;
149 32 : nndataset->magic = ML_NNTRAINER_MAGIC;
150 32 : nndataset->in_use = false;
151 :
152 51 : returnable f = [&]() {
153 19 : if (train != nullptr) {
154 37 : nndataset->dataset[ML_TRAIN_DATASET_MODE_TRAIN] =
155 : ml::train::createDataset(type, train);
156 : }
157 18 : if (valid != nullptr) {
158 8 : nndataset->dataset[ML_TRAIN_DATASET_MODE_VALID] =
159 : ml::train::createDataset(type, valid);
160 : }
161 18 : if (test != nullptr) {
162 6 : nndataset->dataset[ML_TRAIN_DATASET_MODE_TEST] =
163 : ml::train::createDataset(type, test);
164 : }
165 18 : return ML_ERROR_NONE;
166 : };
167 :
168 32 : status = nntrainer_exception_boundary(f);
169 32 : if (status != ML_ERROR_NONE) {
170 2 : delete nndataset;
171 2 : ml_loge("Error: Create dataset failed");
172 : } else {
173 31 : *dataset = nndataset;
174 : }
175 :
176 : return status;
177 : }
178 :
179 : /**
180 : * @brief add ml::train::Dataset to @a dataset
181 : *
182 : * @tparam Args args needed to create the dataset
183 : * @param dataset dataset handle
184 : * @param mode target mode
185 : * @param type dataset type
186 : * @param args args needed to create the dataset
187 : * @retval #ML_ERROR_NONE Successful
188 : * @retval #ML_ERROR_INVALID_PARAMETER if parameter is invalid
189 : */
190 : template <typename... Args>
191 16 : static int ml_train_dataset_add_(ml_train_dataset_h dataset,
192 : ml_train_dataset_mode_e mode,
193 : ml::train::DatasetType type, Args &&...args) {
194 : check_feature_state();
195 16 : std::shared_ptr<ml::train::Dataset> underlying_dataset;
196 :
197 32 : returnable f = [&]() {
198 42 : underlying_dataset =
199 : ml::train::createDataset(type, std::forward<Args>(args)...);
200 15 : return ML_ERROR_NONE;
201 : };
202 :
203 16 : int status = nntrainer_exception_boundary(f);
204 16 : if (status != ML_ERROR_NONE) {
205 1 : ml_loge("Failed to create dataset");
206 1 : return status;
207 : }
208 :
209 15 : if (underlying_dataset == nullptr) {
210 : return ML_ERROR_INVALID_PARAMETER;
211 : }
212 :
213 : ml_train_dataset *nndataset;
214 16 : ML_TRAIN_VERIFY_VALID_HANDLE(dataset);
215 :
216 : {
217 14 : ML_TRAIN_GET_VALID_DATASET_LOCKED(nndataset, dataset);
218 : ML_TRAIN_ADOPT_LOCK(nndataset, dataset_lock);
219 :
220 14 : nndataset->dataset[mode] = underlying_dataset;
221 : }
222 14 : return status;
223 : }
224 :
225 : #ifdef __cplusplus
226 : extern "C" {
227 : #endif
228 :
229 : /**
230 : * @brief Function to create ml::train::Model object.
231 : */
232 46 : static int nn_object(ml_train_model_h *model) {
233 : int status = ML_ERROR_NONE;
234 :
235 46 : if (model == NULL)
236 : return ML_ERROR_INVALID_PARAMETER;
237 :
238 45 : ml_train_model *nnmodel = new ml_train_model;
239 45 : nnmodel->magic = ML_NNTRAINER_MAGIC;
240 45 : nnmodel->optimizer = NULL;
241 45 : nnmodel->dataset = NULL;
242 :
243 45 : *model = nnmodel;
244 :
245 45 : returnable f = [&]() {
246 90 : nnmodel->model = ml::train::createModel(ml::train::ModelType::NEURAL_NET);
247 45 : return ML_ERROR_NONE;
248 : };
249 :
250 45 : status = nntrainer_exception_boundary(f);
251 45 : if (status != ML_ERROR_NONE) {
252 0 : delete nnmodel;
253 0 : ml_loge("Error: creating nn object failed");
254 : }
255 :
256 : return status;
257 : }
258 :
259 46 : int ml_train_model_construct(ml_train_model_h *model) {
260 : int status = ML_ERROR_NONE;
261 :
262 : check_feature_state();
263 :
264 46 : returnable f = [&]() { return nn_object(model); };
265 :
266 46 : status = nntrainer_exception_boundary(f);
267 46 : return status;
268 : }
269 :
270 25 : int ml_train_model_construct_with_conf(const char *model_conf,
271 : ml_train_model_h *model) {
272 : int status = ML_ERROR_NONE;
273 : ml_train_model *nnmodel;
274 25 : std::shared_ptr<ml::train::Model> m;
275 : returnable f;
276 :
277 25 : status = ml_train_model_construct(model);
278 25 : if (status != ML_ERROR_NONE)
279 : return status;
280 :
281 25 : nnmodel = (ml_train_model *)(*model);
282 : m = nnmodel->model;
283 :
284 75 : f = [&]() { return m->loadFromConfig(model_conf); };
285 25 : status = nntrainer_exception_boundary(f);
286 25 : if (status != ML_ERROR_NONE) {
287 2 : ml_train_model_destroy(*model);
288 : }
289 :
290 : return status;
291 : }
292 :
293 25 : int ml_train_model_compile(ml_train_model_h model, ...) {
294 : int status = ML_ERROR_NONE;
295 : const char *data;
296 : ml_train_model *nnmodel;
297 : returnable f;
298 25 : std::shared_ptr<ml::train::Model> m;
299 :
300 : check_feature_state();
301 :
302 26 : ML_TRAIN_VERIFY_VALID_HANDLE(model);
303 :
304 : std::vector<std::string> arg_list;
305 : va_list arguments;
306 24 : va_start(arguments, model);
307 :
308 35 : while ((data = va_arg(arguments, const char *))) {
309 22 : arg_list.push_back(data);
310 : }
311 24 : va_end(arguments);
312 :
313 : {
314 24 : ML_TRAIN_GET_VALID_MODEL_LOCKED(nnmodel, model);
315 : ML_TRAIN_ADOPT_LOCK(nnmodel, model_lock);
316 : m = nnmodel->model;
317 : }
318 :
319 48 : f = [&]() {
320 24 : m->setProperty(arg_list);
321 : return ML_ERROR_NONE;
322 24 : };
323 24 : status = nntrainer_exception_boundary(f);
324 24 : if (status != ML_ERROR_NONE)
325 : return status;
326 :
327 42 : f = [&]() { return m->compile(); };
328 21 : status = nntrainer_exception_boundary(f);
329 21 : if (status != ML_ERROR_NONE)
330 : return status;
331 :
332 42 : f = [&]() { return m->initialize(); };
333 21 : status = nntrainer_exception_boundary(f);
334 : if (status != ML_ERROR_NONE)
335 : return status;
336 :
337 : return status;
338 24 : }
339 :
340 4 : int ml_train_model_compile_with_single_param(ml_train_model_h model,
341 : const char *single_param) {
342 4 : ML_TRAIN_VERIFY_VALID_HANDLE(model);
343 :
344 4 : return ml_train_model_compile(model, single_param, NULL);
345 : }
346 :
347 10 : int ml_train_model_run(ml_train_model_h model, ...) {
348 : int status = ML_ERROR_NONE;
349 : ml_train_model *nnmodel;
350 : const char *data;
351 10 : std::shared_ptr<ml::train::Model> m;
352 :
353 : check_feature_state();
354 :
355 11 : ML_TRAIN_VERIFY_VALID_HANDLE(model);
356 :
357 : std::vector<std::string> arg_list;
358 : va_list arguments;
359 9 : va_start(arguments, model);
360 :
361 19 : while ((data = va_arg(arguments, const char *))) {
362 20 : arg_list.push_back(data);
363 : }
364 :
365 9 : va_end(arguments);
366 :
367 : {
368 9 : ML_TRAIN_GET_VALID_MODEL_LOCKED(nnmodel, model);
369 : ML_TRAIN_ADOPT_LOCK(nnmodel, model_lock);
370 : m = nnmodel->model;
371 : }
372 :
373 23 : returnable f = [&]() { return m->train(arg_list); };
374 9 : status = nntrainer_exception_boundary(f);
375 :
376 : return status;
377 9 : }
378 :
379 4 : int ml_train_model_run_with_single_param(ml_train_model_h model,
380 : const char *single_param) {
381 4 : ML_TRAIN_VERIFY_VALID_HANDLE(model);
382 :
383 4 : return ml_train_model_run(model, single_param, NULL);
384 : }
385 :
386 46 : int ml_train_model_destroy(ml_train_model_h model) {
387 : int status = ML_ERROR_NONE;
388 : ml_train_model *nnmodel;
389 :
390 : check_feature_state();
391 :
392 : {
393 92 : ML_TRAIN_GET_VALID_MODEL_LOCKED_RESET(nnmodel, model);
394 : ML_TRAIN_ADOPT_LOCK(nnmodel, model_lock);
395 : }
396 :
397 45 : if (nnmodel->optimizer) {
398 6 : if (nnmodel->optimizer->lr_scheduler) {
399 2 : ML_TRAIN_RESET_VALIDATED_HANDLE(nnmodel->optimizer->lr_scheduler);
400 4 : delete nnmodel->optimizer->lr_scheduler;
401 : }
402 :
403 6 : ML_TRAIN_RESET_VALIDATED_HANDLE(nnmodel->optimizer);
404 12 : delete nnmodel->optimizer;
405 : }
406 :
407 45 : if (nnmodel->dataset) {
408 5 : ML_TRAIN_RESET_VALIDATED_HANDLE(nnmodel->dataset);
409 10 : delete nnmodel->dataset;
410 : }
411 :
412 69 : for (auto &x : nnmodel->layers_map) {
413 24 : ML_TRAIN_RESET_VALIDATED_HANDLE(x.second);
414 48 : delete (x.second);
415 : }
416 :
417 45 : delete nnmodel;
418 :
419 45 : 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 : int status = ML_ERROR_NONE;
426 : ml_train_model *nnmodel;
427 16 : std::shared_ptr<ml::train::Model> m;
428 :
429 : {
430 32 : ML_TRAIN_GET_VALID_MODEL_LOCKED(nnmodel, model);
431 : ML_TRAIN_ADOPT_LOCK(nnmodel, model_lock);
432 :
433 : m = nnmodel->model;
434 : }
435 :
436 0 : returnable f = [&]() {
437 16 : m->summarize(ss, verbosity);
438 : return ML_ERROR_NONE;
439 16 : };
440 :
441 16 : status = nntrainer_exception_boundary(f);
442 : 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 : int status = ML_ERROR_NONE;
449 17 : std::stringstream ss;
450 :
451 : 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 1 : 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 0 : return status;
464 : }
465 :
466 : std::string str = ss.str();
467 : 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 0 : return ML_ERROR_OUT_OF_MEMORY;
477 : }
478 : std::memcpy(*summary, str.c_str(), size + 1);
479 :
480 16 : return status;
481 17 : }
482 :
483 25 : int ml_train_model_add_layer(ml_train_model_h model, ml_train_layer_h layer) {
484 : int status = ML_ERROR_NONE;
485 : ml_train_model *nnmodel;
486 : ml_train_layer *nnlayer;
487 :
488 : check_feature_state();
489 :
490 50 : ML_TRAIN_GET_VALID_MODEL_LOCKED(nnmodel, model);
491 : ML_TRAIN_ADOPT_LOCK(nnmodel, model_lock);
492 50 : ML_TRAIN_GET_VALID_LAYER_LOCKED(nnlayer, layer);
493 : ML_TRAIN_ADOPT_LOCK(nnlayer, layer_lock);
494 :
495 24 : if (nnlayer->in_use) {
496 0 : ml_loge("Layer already in use.");
497 0 : 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 : m = nnmodel->model;
504 : l = nnlayer->layer;
505 :
506 48 : if (nnmodel->layers_map.count(l->getName())) {
507 4 : 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 44 : 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 21 : 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 : int status = ML_ERROR_NONE;
526 : ml_train_model *nnmodel;
527 : ml_train_optimizer *nnopt;
528 :
529 : check_feature_state();
530 :
531 12 : ML_TRAIN_GET_VALID_MODEL_LOCKED(nnmodel, model);
532 : ML_TRAIN_ADOPT_LOCK(nnmodel, model_lock);
533 12 : ML_TRAIN_GET_VALID_OPT_LOCKED(nnopt, optimizer);
534 : ML_TRAIN_ADOPT_LOCK(nnopt, opt_lock);
535 :
536 6 : if (nnopt->in_use) {
537 0 : ml_loge("Optimizer already in use.");
538 0 : 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 : m = nnmodel->model;
545 : opt = nnopt->optimizer;
546 :
547 12 : 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 : return status;
559 : }
560 :
561 7 : int ml_train_model_set_dataset(ml_train_model_h model,
562 : ml_train_dataset_h dataset) {
563 : int status = ML_ERROR_NONE;
564 : ml_train_model *nnmodel;
565 : ml_train_dataset *nndataset;
566 :
567 : check_feature_state();
568 :
569 14 : ML_TRAIN_GET_VALID_MODEL_LOCKED(nnmodel, model);
570 : ML_TRAIN_ADOPT_LOCK(nnmodel, model_lock);
571 14 : ML_TRAIN_GET_VALID_DATASET_LOCKED(nndataset, dataset);
572 6 : ML_TRAIN_ADOPT_LOCK(nndataset, dataset_lock);
573 :
574 6 : if (nndataset->in_use) {
575 0 : ml_loge("Dataset already in use.");
576 0 : return ML_ERROR_INVALID_PARAMETER;
577 : }
578 :
579 6 : std::shared_ptr<ml::train::Model> m;
580 :
581 : m = nnmodel->model;
582 :
583 6 : returnable f = [&]() {
584 6 : auto &[train_set, valid_set, test_set] = nndataset->dataset;
585 : int status = ML_ERROR_NONE;
586 6 : status = m->setDataset(ml::train::DatasetModeType::MODE_TRAIN, train_set);
587 6 : if (status != ML_ERROR_NONE) {
588 : return status;
589 : }
590 :
591 6 : 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 6 : 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 : };
606 :
607 6 : status = nntrainer_exception_boundary(f);
608 6 : if (status == ML_ERROR_NONE) {
609 6 : nndataset->in_use = true;
610 6 : if (nnmodel->dataset)
611 1 : nnmodel->dataset->in_use = false;
612 6 : nnmodel->dataset = nndataset;
613 : }
614 :
615 : 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 : int status = ML_ERROR_NONE;
621 : ml_train_model *nnmodel;
622 :
623 : check_feature_state();
624 :
625 24 : ML_TRAIN_GET_VALID_MODEL_LOCKED(nnmodel, model);
626 : ML_TRAIN_ADOPT_LOCK(nnmodel, model_lock);
627 :
628 : std::unordered_map<std::string, ml_train_layer *>::iterator layer_iter =
629 12 : 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 6 : std::shared_ptr<ml::train::Model> m;
641 6 : std::shared_ptr<ml::train::Layer> l;
642 :
643 : m = nnmodel->model;
644 12 : 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 : 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 51 : int ml_train_layer_create(ml_train_layer_h *layer, ml_train_layer_type_e type) {
661 : int status = ML_ERROR_NONE;
662 : ml_train_layer *nnlayer;
663 :
664 : check_feature_state();
665 :
666 51 : nnlayer = new ml_train_layer;
667 51 : nnlayer->magic = ML_NNTRAINER_MAGIC;
668 51 : nnlayer->in_use = false;
669 :
670 51 : returnable f = [&]() {
671 101 : nnlayer->layer = ml::train::createLayer((ml::train::LayerType)type);
672 50 : return ML_ERROR_NONE;
673 : };
674 :
675 51 : status = nntrainer_exception_boundary(f);
676 51 : if (status != ML_ERROR_NONE) {
677 2 : delete nnlayer;
678 2 : ml_loge("Error: Create layer failed");
679 : } else {
680 50 : *layer = nnlayer;
681 : }
682 :
683 51 : return status;
684 : }
685 :
686 31 : int ml_train_layer_destroy(ml_train_layer_h layer) {
687 : int status = ML_ERROR_NONE;
688 : ml_train_layer *nnlayer;
689 :
690 : check_feature_state();
691 :
692 : {
693 62 : ML_TRAIN_GET_VALID_LAYER_LOCKED_RESET(nnlayer, layer);
694 : ML_TRAIN_ADOPT_LOCK(nnlayer, layer_lock);
695 :
696 31 : if (nnlayer->in_use) {
697 4 : ml_loge("Cannot delete layer already added in a model."
698 : "Delete model will delete this layer.");
699 : return ML_ERROR_INVALID_PARAMETER;
700 : }
701 : }
702 :
703 29 : delete nnlayer;
704 :
705 29 : return status;
706 : }
707 :
708 72 : int ml_train_layer_set_property(ml_train_layer_h layer, ...) {
709 : int status = ML_ERROR_NONE;
710 : ml_train_layer *nnlayer;
711 : const char *data;
712 72 : std::shared_ptr<ml::train::Layer> l;
713 :
714 : check_feature_state();
715 :
716 77 : ML_TRAIN_VERIFY_VALID_HANDLE(layer);
717 :
718 : std::vector<std::string> arg_list;
719 : va_list arguments;
720 67 : va_start(arguments, layer);
721 :
722 189 : while ((data = va_arg(arguments, const char *))) {
723 244 : arg_list.push_back(data);
724 : }
725 :
726 67 : va_end(arguments);
727 :
728 : {
729 67 : ML_TRAIN_GET_VALID_LAYER_LOCKED(nnlayer, layer);
730 : ML_TRAIN_ADOPT_LOCK(nnlayer, layer_lock);
731 :
732 : l = nnlayer->layer;
733 : }
734 :
735 : returnable f = [&]() {
736 67 : l->setProperty(arg_list);
737 : return ML_ERROR_NONE;
738 : };
739 67 : status = nntrainer_exception_boundary(f);
740 :
741 : return status;
742 67 : }
743 :
744 6 : int ml_train_layer_set_property_with_single_param(ml_train_layer_h layer,
745 : const char *single_param) {
746 6 : ML_TRAIN_VERIFY_VALID_HANDLE(layer);
747 :
748 6 : 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 : int status = ML_ERROR_NONE;
754 :
755 : 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 20 : returnable f = [&]() {
763 19 : nnopt->optimizer =
764 39 : ml::train::createOptimizer((ml::train::OptimizerType)type);
765 19 : return ML_ERROR_NONE;
766 : };
767 :
768 20 : status = nntrainer_exception_boundary(f);
769 20 : if (status != ML_ERROR_NONE) {
770 2 : delete nnopt;
771 2 : ml_loge("creating optimizer failed");
772 : } else {
773 19 : *optimizer = nnopt;
774 : }
775 :
776 20 : return status;
777 : }
778 :
779 15 : int ml_train_optimizer_destroy(ml_train_optimizer_h optimizer) {
780 : int status = ML_ERROR_NONE;
781 : ml_train_optimizer *nnopt;
782 :
783 : check_feature_state();
784 :
785 : {
786 30 : ML_TRAIN_GET_VALID_OPT_LOCKED_RESET(nnopt, optimizer);
787 : ML_TRAIN_ADOPT_LOCK(nnopt, optimizer_lock);
788 :
789 14 : if (nnopt->in_use) {
790 2 : ml_loge("Cannot delete optimizer already set to a model."
791 : "Delete model will delete this optimizer.");
792 : return ML_ERROR_INVALID_PARAMETER;
793 : }
794 : }
795 :
796 13 : if (nnopt->lr_scheduler) {
797 2 : ML_TRAIN_RESET_VALIDATED_HANDLE(nnopt->lr_scheduler);
798 4 : delete nnopt->lr_scheduler;
799 : }
800 :
801 13 : delete nnopt;
802 13 : return status;
803 : }
804 :
805 16 : int ml_train_optimizer_set_property(ml_train_optimizer_h optimizer, ...) {
806 : int status = ML_ERROR_NONE;
807 : ml_train_optimizer *nnopt;
808 : const char *data;
809 16 : std::shared_ptr<ml::train::Optimizer> opt;
810 :
811 : check_feature_state();
812 :
813 17 : ML_TRAIN_VERIFY_VALID_HANDLE(optimizer);
814 :
815 : std::vector<std::string> arg_list;
816 : 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 : {
826 15 : ML_TRAIN_GET_VALID_OPT_LOCKED(nnopt, optimizer);
827 : ML_TRAIN_ADOPT_LOCK(nnopt, optimizer_lock);
828 :
829 : opt = nnopt->optimizer;
830 : }
831 :
832 : returnable f = [&]() {
833 15 : opt->setProperty(arg_list);
834 : return ML_ERROR_NONE;
835 : };
836 :
837 15 : status = nntrainer_exception_boundary(f);
838 :
839 : return status;
840 15 : }
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 : int status = ML_ERROR_NONE;
852 : ml_train_optimizer *nnopt;
853 : ml_train_lr_scheduler *nnlrscheduler;
854 :
855 : 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 : {
861 8 : ML_TRAIN_GET_VALID_OPT_LOCKED(nnopt, optimizer);
862 : ML_TRAIN_ADOPT_LOCK(nnopt, opt_lock);
863 : opt = nnopt->optimizer;
864 : }
865 :
866 : {
867 8 : ML_TRAIN_GET_VALID_LR_SCHEDULER_LOCKED(nnlrscheduler, lr_scheduler);
868 : ML_TRAIN_ADOPT_LOCK(nnlrscheduler, lr_scheduler_lock);
869 : lr_sched = nnlrscheduler->lr_scheduler;
870 : }
871 :
872 4 : if (nnlrscheduler->in_use) {
873 0 : ml_loge("learning rate scheduler already in use.");
874 0 : return ML_ERROR_INVALID_PARAMETER;
875 : }
876 :
877 8 : 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 : 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 : int status = ML_ERROR_NONE;
894 :
895 : 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 20 : returnable f = [&]() {
902 19 : nnlrscheduler->lr_scheduler = ml::train::createLearningRateScheduler(
903 39 : (ml::train::LearningRateSchedulerType)type);
904 19 : return ML_ERROR_NONE;
905 : };
906 :
907 20 : status = nntrainer_exception_boundary(f);
908 20 : if (status != ML_ERROR_NONE) {
909 2 : delete nnlrscheduler;
910 2 : 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 : int status = ML_ERROR_NONE;
920 : ml_train_lr_scheduler *nnlrscheduler;
921 :
922 : check_feature_state();
923 :
924 : {
925 36 : ML_TRAIN_GET_VALID_LR_SCHEDULER_LOCKED_RESET(nnlrscheduler, lr_scheduler);
926 : ML_TRAIN_ADOPT_LOCK(nnlrscheduler, lr_scheduler_lock);
927 :
928 17 : if (nnlrscheduler->in_use) {
929 4 : ml_loge(
930 : "Cannot delete learning rate scheduler already set to a optimizer."
931 : "Delete optimizer will delete this learning rate scheduler.");
932 : 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 : int status = ML_ERROR_NONE;
943 : ml_train_lr_scheduler *nnlrscheduler;
944 : const char *data;
945 14 : std::shared_ptr<ml::train::LearningRateScheduler> lr_sched;
946 :
947 : check_feature_state();
948 :
949 14 : ML_TRAIN_VERIFY_VALID_HANDLE(lr_scheduler);
950 :
951 : std::vector<std::string> arg_list;
952 : 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 : {
962 14 : ML_TRAIN_GET_VALID_LR_SCHEDULER_LOCKED(nnlrscheduler, lr_scheduler);
963 : ML_TRAIN_ADOPT_LOCK(nnlrscheduler, lr_scheduler_lock);
964 :
965 : lr_sched = nnlrscheduler->lr_scheduler;
966 : }
967 :
968 : returnable f = [&]() {
969 14 : lr_sched->setProperty(arg_list);
970 : return ML_ERROR_NONE;
971 : };
972 :
973 14 : status = nntrainer_exception_boundary(f);
974 :
975 : return status;
976 14 : }
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 14 : int ml_train_dataset_create(ml_train_dataset_h *dataset) {
986 14 : return ml_train_dataset_create(dataset, ml::train::DatasetType::UNKNOWN,
987 14 : nullptr, nullptr, nullptr);
988 : }
989 :
990 14 : 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 : check_feature_state();
994 14 : if (cb == nullptr) {
995 : return ML_ERROR_INVALID_PARAMETER;
996 : }
997 :
998 11 : return ml_train_dataset_add_(dataset, mode, ml::train::DatasetType::GENERATOR,
999 11 : 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 : 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 36 : 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 : static constexpr char USER_DATA[] = "user_data";
1052 : int status = ML_ERROR_NONE;
1053 : ml_train_dataset *nndataset;
1054 :
1055 : check_feature_state();
1056 :
1057 38 : ML_TRAIN_VERIFY_VALID_HANDLE(dataset);
1058 :
1059 : {
1060 34 : ML_TRAIN_GET_VALID_DATASET_LOCKED(nndataset, dataset);
1061 : ML_TRAIN_ADOPT_LOCK(nndataset, dataset_lock);
1062 :
1063 34 : auto &db = nndataset->dataset[mode];
1064 :
1065 34 : returnable f = [&db, &args]() {
1066 : int status_ = ML_ERROR_NONE;
1067 34 : if (db == nullptr) {
1068 : status_ = ML_ERROR_NOT_SUPPORTED;
1069 : return status_;
1070 : }
1071 :
1072 : std::vector<std::string> properties;
1073 36 : for (unsigned int i = 0; i < args.size(); ++i) {
1074 19 : char *key_ptr = (char *)args[i];
1075 19 : std::string key = key_ptr;
1076 : std::for_each(key.begin(), key.end(),
1077 243 : [](char &c) { c = ::tolower(c); });
1078 19 : 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 19 : 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 : 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 : i++;
1096 32 : } 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 : status_ = ML_ERROR_INVALID_PARAMETER;
1100 : return status_;
1101 : } else {
1102 14 : properties.push_back(key);
1103 : continue;
1104 : }
1105 : }
1106 :
1107 17 : db->setProperty(properties);
1108 : return status_;
1109 19 : };
1110 :
1111 34 : status = nntrainer_exception_boundary(f);
1112 : }
1113 34 : return status;
1114 : }
1115 :
1116 11 : int ml_train_dataset_set_property(ml_train_dataset_h dataset, ...) {
1117 : std::vector<void *> arg_list;
1118 : va_list arguments;
1119 11 : va_start(arguments, dataset);
1120 :
1121 : 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 11 : }
1148 :
1149 13 : int ml_train_dataset_set_property_for_mode(ml_train_dataset_h dataset,
1150 : ml_train_dataset_mode_e mode, ...) {
1151 : std::vector<void *> arg_list;
1152 : va_list arguments;
1153 13 : va_start(arguments, mode);
1154 :
1155 : void *data;
1156 28 : while ((data = va_arg(arguments, void *))) {
1157 15 : arg_list.push_back(data);
1158 : }
1159 13 : va_end(arguments);
1160 :
1161 13 : int status = ml_train_dataset_set_property_for_mode_(dataset, mode, arg_list);
1162 :
1163 26 : return status != ML_ERROR_NONE ? ML_ERROR_INVALID_PARAMETER : ML_ERROR_NONE;
1164 13 : }
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 : int status = ML_ERROR_NONE;
1177 : ml_train_dataset *nndataset;
1178 :
1179 : check_feature_state();
1180 :
1181 : {
1182 58 : ML_TRAIN_GET_VALID_DATASET_LOCKED_RESET(nndataset, dataset);
1183 : ML_TRAIN_ADOPT_LOCK(nndataset, dataset_lock);
1184 :
1185 28 : if (nndataset->in_use) {
1186 4 : ml_loge("Cannot delete dataset already set to a model."
1187 : "Delete model will delete this dataset.");
1188 : 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 : int status = ML_ERROR_NONE;
1199 : ml_train_model *nnmodel;
1200 6 : std::shared_ptr<ml::train::Model> m;
1201 : returnable f;
1202 :
1203 : check_feature_state();
1204 :
1205 6 : if (!info) {
1206 : return ML_ERROR_INVALID_PARAMETER;
1207 : }
1208 :
1209 12 : ML_TRAIN_GET_VALID_MODEL_LOCKED(nnmodel, model);
1210 : ML_TRAIN_ADOPT_LOCK(nnmodel, model_lock);
1211 : m = nnmodel->model;
1212 4 : if (m == NULL) {
1213 : return ML_ERROR_INVALID_PARAMETER;
1214 : }
1215 :
1216 : std::vector<ml::train::TensorDim> dims;
1217 12 : 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 : 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 : return status;
1253 : }
1254 3 : }
1255 :
1256 : return status;
1257 4 : }
1258 :
1259 6 : int ml_train_model_get_output_tensors_info(ml_train_model_h model,
1260 : ml_tensors_info_h *info) {
1261 : int status = ML_ERROR_NONE;
1262 : ml_train_model *nnmodel;
1263 6 : std::shared_ptr<ml::train::Model> m;
1264 : returnable f;
1265 :
1266 : check_feature_state();
1267 :
1268 6 : if (!info) {
1269 : return ML_ERROR_INVALID_PARAMETER;
1270 : }
1271 :
1272 12 : ML_TRAIN_GET_VALID_MODEL_LOCKED(nnmodel, model);
1273 : ML_TRAIN_ADOPT_LOCK(nnmodel, model_lock);
1274 : m = nnmodel->model;
1275 4 : if (m == NULL) {
1276 : return ML_ERROR_INVALID_PARAMETER;
1277 : }
1278 :
1279 : std::vector<ml::train::TensorDim> dims;
1280 :
1281 12 : 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 : 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 : return status;
1317 : }
1318 3 : }
1319 :
1320 : return status;
1321 4 : }
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 : int status = ML_ERROR_NONE;
1326 : ml_train_model *nnmodel;
1327 0 : std::shared_ptr<ml::train::Model> m;
1328 :
1329 : {
1330 0 : ML_TRAIN_GET_VALID_MODEL_LOCKED(nnmodel, model);
1331 : ML_TRAIN_ADOPT_LOCK(nnmodel, model_lock);
1332 :
1333 : 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 : 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 : int status = ML_ERROR_NONE;
1348 : ml_train_model *nnmodel;
1349 0 : std::shared_ptr<ml::train::Model> m;
1350 :
1351 : {
1352 0 : ML_TRAIN_GET_VALID_MODEL_LOCKED(nnmodel, model);
1353 : ML_TRAIN_ADOPT_LOCK(nnmodel, model_lock);
1354 :
1355 : 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 : 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 : int status = ML_ERROR_NONE;
1371 : ml_train_model *nnmodel;
1372 :
1373 : check_feature_state();
1374 :
1375 2 : ML_TRAIN_GET_VALID_MODEL_LOCKED(nnmodel, model);
1376 : 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 : std::vector<float *> w;
1381 : std::vector<ml::train::TensorDim> dims;
1382 : std::vector<std::string> weight_name;
1383 :
1384 : m = nnmodel->model;
1385 :
1386 2 : 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 0 : 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 : 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 : 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 2 : }
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 2 : 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 1 : }
1458 :
1459 : #ifdef __cplusplus
1460 : }
1461 : #endif
|