LCOV - code coverage report
Current view: top level - api/capi/src - nntrainer.cpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 88.3 % 538 475
Test Date: 2025-12-14 20:38:17 Functions: 94.1 % 68 64

            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
        

Generated by: LCOV version 2.0-1