LCOV - code coverage report
Current view: top level - nntrainer-0.5.0/api/capi/src - nntrainer.cpp (source / functions) Hit Total Coverage
Test: nntrainer 0.5.0-0 nnstreamer/nntrainer.git#7135f75d29b46a8913396dc62973559febc0ff1d Lines: 682 754 90.5 %
Date: 2023-06-08 09:54:03 Functions: 64 68 94.1 %

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

Generated by: LCOV version 1.16